feat(core): [Network Token] Passing Network Token in payments request#9975
feat(core): [Network Token] Passing Network Token in payments request#9975bernard-eugine merged 10 commits intomainfrom
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #9975 +/- ##
=======================================
Coverage ? 6.42%
=======================================
Files ? 1262
Lines ? 315947
Branches ? 0
=======================================
Hits ? 20292
Misses ? 295655
Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Can we have clear title and description? |
Can you check the solution doc, already attached in the description. |
|
did we test out the pre network tokenization and save card flow for this? |
can you please explain why do we need to test all the flows that include network tokenization? pre network tokenization and save card flow are for cards right? This is a whole new payment method. |
due to poor pr tittle and description, not able to under stand why this is introduced. Can we please follow the commit guidelines - |
cab4658 to
db87d03
Compare
db87d03 to
d9f6764
Compare
Can you check the PR description? The solution doc is already attached to it, the problem statement and expected solution is mentioned over there. Also I attached a github issue, renamed the title. can you review the PR now? |
prasunna09
left a comment
There was a problem hiding this comment.
also, observed that other than passing network token data in payments request,
NetworkTransactionIdAndNetworkTokenDetails has been introduced.
is this intentional? can we list down all the changes done in the description rather than issue or the doc, since not everyone has access to them
crates/api_models/src/mandates.rs
Outdated
|
|
||
| /// The token's network | ||
| #[schema(value_type = Option<CardNetwork>, example = "Visa")] | ||
| pub network: Option<api_enums::CardNetwork>, |
There was a problem hiding this comment.
| pub network: Option<api_enums::CardNetwork>, | |
| pub card_network: Option<api_enums::CardNetwork>, |
crates/api_models/src/mandates.rs
Outdated
| pub struct NetworkTransactionIdAndNetworkTokenDetails { | ||
| /// The Network Token | ||
| #[schema(value_type = String, example = "4242424242424242")] | ||
| pub network_token: cards::CardNumber, |
There was a problem hiding this comment.
Can we use the network token type instead of cardnumber?
crates/api_models/src/payments.rs
Outdated
| pub struct NetworkTokenData { | ||
| /// The network token | ||
| #[schema(value_type = String, example = "4242424242424242")] | ||
| pub network_token: CardNumber, |
There was a problem hiding this comment.
use network token type instead of card number
crates/api_models/src/payments.rs
Outdated
|
|
||
| /// The token cryptogram | ||
| #[schema(value_type = Option<String>)] | ||
| pub token_cryptogram: Option<Secret<String>>, |
There was a problem hiding this comment.
pub card_network: Option<common_enums::CardNetwork>,
pub card_type: Option<payment_methods::CardType>,
pub card_issuing_country: Option<common_enums::CountryAlpha2>,
pub bank_code: Option<String>,
pub card_holder_name: Option<Secret<String>>,
pub nick_name: Option<Secret<String>>,
pub eci: Option<String>,
do we not need these values?please add them
crates/api_models/src/payments.rs
Outdated
|
|
||
| /// The token cryptogram | ||
| #[schema(value_type = Option<String>)] | ||
| pub token_cryptogram: Option<Secret<String>>, |
There was a problem hiding this comment.
why is cryptogram optional?
without cryptogram, network token cannot be processed
crates/api_models/src/payments.rs
Outdated
| dt.network_token | ||
| .peek() | ||
| .clone() | ||
| .chars() | ||
| .rev() | ||
| .take(4) | ||
| .collect::<String>() | ||
| .chars() | ||
| .rev() | ||
| .collect::<String>() | ||
| }), |
There was a problem hiding this comment.
can we write get method for this
|
|
||
| #[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)] | ||
| pub struct NetworkTokenDetailsForNetworkTransactionId { | ||
| pub network_token: cards::CardNumber, |
|
also can we fix the clippy for both v1 and v2? |
3d3fa06 to
fb1a943
Compare
| pub struct NetworkTokenData { | ||
| /// The network token | ||
| #[schema(value_type = String, example = "4242424242424242")] | ||
| #[smithy(value_type = "String")] | ||
| pub network_token: NetworkToken, | ||
|
|
||
| /// The token's expiry month | ||
| #[schema(value_type = String, example = "05")] | ||
| #[smithy(value_type = "String")] | ||
| pub token_exp_month: Secret<String>, | ||
|
|
||
| /// The token's expiry year | ||
| #[schema(value_type = String, example = "24")] | ||
| #[smithy(value_type = "String")] | ||
| pub token_exp_year: Secret<String>, | ||
|
|
||
| /// The token cryptogram | ||
| #[schema(value_type = String)] | ||
| #[smithy(value_type = "String")] | ||
| pub token_cryptogram: Secret<String>, | ||
|
|
||
| /// The card network for the card | ||
| #[schema(value_type = Option<CardNetwork>, example = "Visa")] | ||
| #[smithy(value_type = "Option<CardNetwork>")] | ||
| pub card_network: Option<api_enums::CardNetwork>, | ||
|
|
||
| #[schema(example = "CREDIT")] | ||
| #[smithy(value_type = "Option<String>")] | ||
| pub card_type: Option<String>, | ||
|
|
||
| #[schema(example = "INDIA")] | ||
| #[smithy(value_type = "Option<String>")] | ||
| pub card_issuing_country: Option<String>, | ||
|
|
||
| #[schema(example = "JP_AMEX")] | ||
| #[smithy(value_type = "Option<String>")] | ||
| pub bank_code: Option<String>, |
There was a problem hiding this comment.
since this is in payment request, what happens if you pass customer acceptance along with this payment methods data?
Can you please add that test case and attach screenshot for future reference?
There was a problem hiding this comment.
added screenshot
| /// The card network for the card | ||
| #[schema(value_type = Option<CardNetwork>, example = "Visa")] | ||
| #[smithy(value_type = "Option<CardNetwork>")] | ||
| pub card_network: Option<api_enums::CardNetwork>, |
There was a problem hiding this comment.
can we use card info table to update card network in core?
or will it always be empty if not passed in the request?
There was a problem hiding this comment.
It will be empty of not passed in the request
There was a problem hiding this comment.
can we use card info table to update card network in core?
or will it always be empty if not passed in the request?
The new cards info dump that we have contains the row for network tokens as well. We will be able to populate this once the new details is available in the db
| pub token_exp_year: Option<Secret<String>>, | ||
|
|
||
| pub card_holder_name: Option<Secret<String>>, | ||
| } |
There was a problem hiding this comment.
please add respective doc comments
| api_models::enums::PaymentMethod::NetworkToken => { | ||
| // NetworkToken is not yet supported in the response modifier | ||
| } |
There was a problem hiding this comment.
why is this used?
and why is it empty for network token? is it intentional?
| let transaction_type = if item.request.off_session == Some(true) { | ||
| TransactionType::StoredCredentials | ||
| } else { | ||
| TransactionType::InApp | ||
| }; | ||
|
|
||
| ( | ||
| PaymentInformation::NetworkToken(Box::new(NetworkTokenPaymentInformation { | ||
| tokenized_card: NetworkTokenizedCard { | ||
| number: token_data.get_network_token(), | ||
| expiration_month: token_data.get_network_token_expiry_month(), | ||
| expiration_year: token_data.get_network_token_expiry_year(), | ||
| cryptogram: token_data.get_cryptogram().clone(), | ||
| transaction_type, | ||
| }, | ||
| })), | ||
| None, | ||
| ) |
There was a problem hiding this comment.
why are we having cybersource support in this pr?
Can we now put it under not implemented, and raise sepperate pr for this?
| #[cfg(feature = "v1")] | ||
| fn get_card_issuer(&self) -> Result<CardIssuer, Error> { | ||
| get_card_issuer(self.network_token.peek()) | ||
| } | ||
|
|
||
| #[cfg(feature = "v2")] | ||
| fn get_card_issuer(&self) -> Result<CardIssuer, Error> { | ||
| get_card_issuer(self.network_token.peek()) | ||
| } | ||
|
|
||
| #[cfg(feature = "v1")] | ||
| fn get_expiry_year_4_digit(&self) -> Secret<String> { | ||
| let mut year = self.token_exp_year.peek().clone(); | ||
| if year.len() == 2 { | ||
| year = format!("20{year}"); | ||
| } | ||
| Secret::new(year) | ||
| } | ||
|
|
||
| #[cfg(feature = "v2")] | ||
| fn get_expiry_year_4_digit(&self) -> Secret<String> { | ||
| let mut year = self.token_exp_year.peek().clone(); | ||
| if year.len() == 2 { | ||
| year = format!("20{year}"); | ||
| } | ||
| Secret::new(year) | ||
| } |
There was a problem hiding this comment.
why do we need v1 and v2 if both impl are same??
| fn get_network_token(&self) -> NetworkTokenNumber { | ||
| self.network_token.clone() | ||
| } | ||
|
|
||
| #[cfg(feature = "v2")] | ||
| fn get_network_token(&self) -> NetworkTokenNumber { | ||
| self.network_token.clone() | ||
| } |
There was a problem hiding this comment.
since we are using Network Token type, why do we need NetworkTokenNumber?
all the commectors can have network token type only.
we dont need NetworkTokenNumber anymore right?
| fn get_cryptogram(&self) -> Option<Secret<String>> { | ||
| None | ||
| } | ||
|
|
||
| #[cfg(feature = "v2")] | ||
| fn get_cryptogram(&self) -> Option<Secret<String>> { | ||
| None | ||
| } |
There was a problem hiding this comment.
NetworkTokenDetailsWithNTI doesn't have the field cryptogram
There was a problem hiding this comment.
get_cryptogram can be used in repeat CIT right?
There was a problem hiding this comment.
since it is a mit flow, cryptogram is not present here.
| pub type NetworkTokenNumber = CardNumber; | ||
|
|
||
| #[cfg(feature = "v2")] | ||
| pub type NetworkTokenNumber = NetworkToken; |
There was a problem hiding this comment.
if we have deprecated, why are having v1 and v2 in utils?
| } | ||
| } | ||
|
|
||
| #[cfg(feature = "v1")] |
There was a problem hiding this comment.
why this should be under v1?
There was a problem hiding this comment.
this should be under v1 because the name of the fields in v2 NetworkTokenData is different. can you please tell me why we have kept the name of the fields different for v1 and v2.
crates/router/src/core/payments.rs
Outdated
| match recurring_payment_details.clone() { | ||
| RecurringDetails::NetworkTransactionIdAndCardDetails(_) => { | ||
| let (mandate_reference_id, card_details_for_network_transaction_id) = | ||
| CardDetailsForNetworkTransactionId::get_nti_and_card_details_for_mit_flow( | ||
| recurring_payment_details.clone(), | ||
| ) | ||
| .get_required_value("network transaction id and card details") | ||
| .attach_printable( | ||
| "Failed to fetch network transaction id and card details for mit", | ||
| )?; | ||
| helpers::validate_card_expiry( | ||
| &card_details_for_network_transaction_id.card_exp_month, | ||
| &card_details_for_network_transaction_id.card_exp_year, | ||
| )?; | ||
|
|
||
| Ok(( | ||
| mandate_reference_id, | ||
| hyperswitch_domain_models::payment_method_data::PaymentMethodData::CardDetailsForNetworkTransactionId(card_details_for_network_transaction_id), | ||
| eligible_connector_data.clone(), | ||
| )) | ||
| } | ||
| RecurringDetails::NetworkTransactionIdAndNetworkTokenDetails(_) => { |
There was a problem hiding this comment.
lets have micro pr for api changes, core changes, and connector changes seperately
There was a problem hiding this comment.
removed the connector related changes, network token and ntid related changes should be in this PR for e2e flow for normal and cit/mits.
146c511 to
0a230fa
Compare
| if cryptogram.trim().is_empty() { | ||
| Err(report!(errors::ApiErrorResponse::PreconditionFailed { | ||
| message: "Invalid token_cryptogram".to_string() | ||
| }))? | ||
| } |
There was a problem hiding this comment.
nit: can use when method from utils
d4a912c
a71f262 to
d4a912c
Compare
…pm-metadata * 'main' of github.com:juspay/hyperswitch: chore(version): 2025.12.22.0 feat(braintree): add UCS wallet support for PaypalSdk, ApplePayThirdPartySdk, and GooglePayThirdPartySdk (#10513) Fix: WorldpayVantiv Cypress fix (#10656) feat(connector): Add Apple Pay HS-Decryption support for Braintree (#10734) ci(cypress): add bank redirect flow onlinebankingfpx for fiuu (#10642) chore(version): 2025.12.19.0 refactor(connector): [paysafe] introduce `PaymentMethodToken` flow (#10541) fix(connectors): add 3ds validations for connector for card specific only (#10560) fix(router): Prevent panic when masking non-ASCII strings (#10682) feat(authentication): add domain models for authentication and support kafka filters in dashboard (#10446) fix(docker): increase RUST_MIN_STACK size to handle stack overflow (#10730) fix(api): align ApiEvent status_code with HTTP response when proxy_connector_http_status_code enabled (#10680) feat(core): [Network Token] Passing Network Token in payments request (#9975) feat(core): Bumped UCS Client dependency to bring latest changes (#10641) ci(cypress): Update cypress shadow mode rollout configs (#10689)
…rmers * 'main' of github.com:juspay/hyperswitch: (67 commits) refactor: Introduce PreAuth for redsys HS<>UCS tunnel (#10727) chore(version): 2025.12.22.0 feat(braintree): add UCS wallet support for PaypalSdk, ApplePayThirdPartySdk, and GooglePayThirdPartySdk (#10513) Fix: WorldpayVantiv Cypress fix (#10656) feat(connector): Add Apple Pay HS-Decryption support for Braintree (#10734) ci(cypress): add bank redirect flow onlinebankingfpx for fiuu (#10642) chore(version): 2025.12.19.0 refactor(connector): [paysafe] introduce `PaymentMethodToken` flow (#10541) fix(connectors): add 3ds validations for connector for card specific only (#10560) fix(router): Prevent panic when masking non-ASCII strings (#10682) feat(authentication): add domain models for authentication and support kafka filters in dashboard (#10446) fix(docker): increase RUST_MIN_STACK size to handle stack overflow (#10730) fix(api): align ApiEvent status_code with HTTP response when proxy_connector_http_status_code enabled (#10680) feat(core): [Network Token] Passing Network Token in payments request (#9975) feat(core): Bumped UCS Client dependency to bring latest changes (#10641) ci(cypress): Update cypress shadow mode rollout configs (#10689) chore(version): 2025.12.18.0 feat(payment-methods): Add support for guest checkout flow in payment method service (#10487) feat(connector): [NMI] Implement Apple Pay - hyperswitch decryption flow (#10686) fix(connector): [bluesnap] pass `connector_request_ref_id` instead of `payment_id` (#10653) ...
Type of Change
Description
Network Token Added as a payment method.
Network Token to be passed directly in Payments Request:
Network Token + CryptogramNetwork Token + NTISolution Doc: https://docs.google.com/document/d/1trPRKzexBHQwGHmDZ_ixqRmcMiaehu3TOpv136JOXsw/edit?usp=sharing
Additional Changes
Motivation and Context
How did you test it?
Response:

Checklist
cargo +nightly fmt --allcargo clippy