Skip to content

feat(core): [Network Token] Passing Network Token in payments request#9975

Merged
bernard-eugine merged 10 commits intomainfrom
network_token_pm
Dec 18, 2025
Merged

feat(core): [Network Token] Passing Network Token in payments request#9975
bernard-eugine merged 10 commits intomainfrom
network_token_pm

Conversation

@ImSagnik007
Copy link
Contributor

@ImSagnik007 ImSagnik007 commented Oct 24, 2025

Type of Change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring
  • Dependency updates
  • Documentation
  • CI/CD

Description

Network Token Added as a payment method.
Network Token to be passed directly in Payments Request:

  1. For normal and CIT payment: Network Token + Cryptogram
#[derive(Default, Eq, PartialEq, Clone, Debug, serde::Deserialize, serde::Serialize, ToSchema)]
pub struct NetworkTokenData {
    /// The network token
    #[schema(value_type = String, example = "4242424242424242")]
    pub network_token: CardNumber,

    /// The token's expiry month
    #[schema(value_type = String, example = "05")]
    pub token_exp_month: Secret<String>,

    /// The token's expiry year
    #[schema(value_type = String, example = "24")]
    pub token_exp_year: Secret<String>,

    /// The token cryptogram
    #[schema(value_type = Option<String>)]
    pub token_cryptogram: Option<Secret<String>>,
}
  1. For MIT payment: Network Token + NTI
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, ToSchema, PartialEq, Eq)]
pub struct NetworkTransactionIdAndNetworkTokenDetails {
    /// The Network Token
    #[schema(value_type = String, example = "4242424242424242")]
    pub network_token: cards::CardNumber,

    /// The token's expiry month
    #[schema(value_type = String, example = "05")]
    pub token_exp_month: Secret<String>,

    /// The token's expiry year
    #[schema(value_type = String, example = "24")]
    pub token_exp_year: Secret<String>,

    /// The token's network
    #[schema(value_type = Option<CardNetwork>, example = "Visa")]
    pub network: Option<api_enums::CardNetwork>,

    /// The network transaction ID provided by the card network during a Customer Initiated Transaction (CIT)
    /// where `off_session` is true.
    #[schema(value_type = String)]
    pub network_transaction_id: Secret<String>,
}

Solution Doc: https://docs.google.com/document/d/1trPRKzexBHQwGHmDZ_ixqRmcMiaehu3TOpv136JOXsw/edit?usp=sharing

Additional Changes

  • This PR modifies the API contract
  • This PR modifies the database schema
  • This PR modifies application configuration/environment variables

Motivation and Context

How did you test it?

  1. Merchant Acc create
  2. API key create
  3. Connector create:
curl --location 'http://localhost:8080/account/merchant_1761292607/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_MARy9LQgElvWpiESgZY3WgYYEGSIBoQmpGDsoheuhAhs0Vj8HpdBOqyvxQOqcvQt' \
--data '{
    "connector_type": "payment_processor",
    "connector_name": "cybersource",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_secret": "",
        "api_key": "",
        "key1": ""
    },
    "test_mode": true,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "google_pay",
                    "payment_experience": "invoke_sdk_client",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "network_token",
            "payment_method_types": [
                {
                    "payment_method_type": "network_token",
                    "payment_experience": null,
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": 1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        },
        {
            "payment_method": "card",
            "payment_method_types": [
                {
                    "payment_method_type": "credit",
                    "payment_experience": null,
                    "card_networks": [
                        "Visa",
                        "Mastercard",
                        "AmericanExpress"
                    ],
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_type": "debit",
                    "payment_experience": null,
                    "card_networks": [
                        "Visa",
                        "Mastercard"
                    ],
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ],
    "metadata": {
        "status_url": "https://2753-2401-4900-1cb8-2ff9-24dd-1ccf-ed12-b464.in.ngrok.io/webhooks/merchant_1678699058/globalpay",
        "account_name": "transaction_processing",
        "pricing_type": "fixed_price",
        "acquirer_bin": "438309",
        "acquirer_merchant_id": "00002000000"
    },
    "business_country": "US",
    "business_label": "default",
    "frm_configs": null,
    "connector_webhook_details": {
        "merchant_secret": ""
    }
}'
  1. Payments create:
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_Qb8sXXnto02KhH9HKhJzN9V5VbfOOXCVJBx3Jmveu14XgHQ3wOOVu5pKTLEOZsHc' \
--data-raw '{
  "amount": 6540,
  "currency": "USD",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 6540,
  "customer_id": "StripeCustomer",
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "setup_future_usage": "on_session",
  "payment_method": "network_token",
  "payment_method_type": "network_token",
  "payment_method_data": {
    "network_token": {
      "network_token": "",
      "token_exp_month": "12",
      "token_exp_year": "26",
      "token_cryptogram": ""
    }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  }
}'
  1. Payments Create CIT:
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_eTv2dhqRaLPG86yfGSYsdpwdkt90Tl0mVFUIfPtKxUVW3RhNryspwSG6930c7LBB' \
--data-raw '{
  "amount": 6540,
  "currency": "USD",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 6540,
  "customer_id": "StripeCustomer",
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "setup_future_usage": "off_session",
  "payment_type": "setup_mandate",
  "payment_method": "network_token",
  "payment_method_type": "network_token",
  "payment_method_data": {
    "network_token": {
      "network_token": "",
      "token_exp_month": "12",
      "token_exp_year": "26",
      "token_cryptogram": ""
    }
  },
  "customer_acceptance": {
        "acceptance_type": "offline",
        "accepted_at": "1963-05-03T04:07:52.723Z",
        "online": {
            "ip_address": "in sit",
            "user_agent": "amet irure esse"
        }
    },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "udf1": "value1",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  }
}'

Response:
Screenshot 2025-11-25 at 1 55 51 AM

  1. Payments Create MIT (pm id):
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_eTv2dhqRaLPG86yfGSYsdpwdkt90Tl0mVFUIfPtKxUVW3RhNryspwSG6930c7LBB' \
--data '{
    "amount": 999,
    "currency": "USD",
    "confirm": true,
    "profile_id": "pro_ArBaOyc24CoPMaqbFx8O",
    "customer_id": "StripeCustomer",
    "return_url": "https://google.com",
    "payment_method": "card",
    "payment_method_type": "credit",
    "recurring_details": {
        "type": "payment_method_id",
        "data": "pm_pMutHGTtUekgMcPgKE1k"
    },
    "off_session": true,
    "billing": {
        "address": {
            "first_name":"John",
            "last_name":"Doe",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US"
        },
         "phone": {
            "number": "8056594427",
            "country_code": "+91"
        }
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    }
    
}'
  1. Payments create MIT (network token + ntid)
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_IclGrZybF0qTMAkfMr7ZHUwcC6R4L3xYiEEjC4lG7DQ32H4TW9jZdujgh8NKvXol' \
--data-raw '{
    "amount": 999,
    "currency": "USD",
    "confirm": true,
    "customer_id": "StripeCustomer",
    "return_url": "https://google.com",
    "payment_method": "network_token",
    "payment_method_type": "network_token",
    "recurring_details": {
        "type": "network_transaction_id_and_network_token_details",
        "data": 
            {
                "network_token": "",
                "token_exp_month": "12",
                "token_exp_year": "26",
                "network_transaction_id": ""
            }
    },
    "off_session": true,
    "billing": {
        "address": {
            "first_name":"John",
            "last_name":"Doe",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "city": "San Fransico",
            "state": "California",
            "zip": "94122",
            "country": "US"
        },
         "phone": {
            "number": "8056594427",
            "country_code": "+91"
        },
        "email": "sagnik.mitra@juspay.in"
    },
    "browser_info": {
        "user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
        "accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "125.0.0.1"
    }
    
}'
  • Payment method entry when network token data is passed in payment request:
{
  "customer_id": "StripeCustomer",
  "merchant_id": "merchant_1764867791",
  "payment_method_id": "pm_eleK3Gm8QnbRhvonEy4T",
  "accepted_currency": null,
  "scheme": null,
  "token": null,
  "cardholder_name": null,
  "issuer_name": null,
  "issuer_country": null,
  "payer_country": null,
  "is_stored": null,
  "swift_code": null,
  "direct_debit_token": null,
  "created_at": "2025-12-04T17:03:34.35882",
  "last_modified": "2025-12-04T17:03:34.448131",
  "payment_method": "network_token",
  "payment_method_type": "network_token",
  "payment_method_issuer": null,
  "payment_method_issuer_code": null,
  "metadata": null,
  "payment_method_data": null,
  "locker_id": null,
  "last_used_at": "2025-12-04T17:03:34.35882",
  "connector_mandate_details": {
    "mca_E2CjV5kYF6yFD62nbQyx": {
      "mandate_metadata": null,
      "payment_method_type": "network_token",
      "connector_mandate_id": "4524351C814EDAA1E063AF598E0A5A6B",
      "connector_customer_id": null,
      "connector_mandate_status": "active",
      "original_payment_authorized_amount": 6540,
      "original_payment_authorized_currency": "USD",
      "connector_mandate_request_reference_id": "szgaQ3ZTFfAnknJqYw"
    }
  },
  "customer_acceptance": {
    "online": {
      "ip_address": "in sit",
      "user_agent": "amet irure esse"
    },
    "accepted_at": "1963-05-03T04:07:52.723Z",
    "acceptance_type": "offline"
  },
  "status": "active",
  "network_transaction_id": "016150703802094",
  "client_secret": "pm_eleK3Gm8QnbRhvonEy4T_secret_8Dscng4x15agE1OLJ367",
  "payment_method_billing_address": "\\x970692166518b083387b40b09888b00f052a2a493304c50b68b535b186cc31785bc952832a71eeea1db30e11917e774a63a43f907435bcaa079458ee44c923c16cdd5fbb1be19980ea00ccc25544803eb29ed6022da802cb7addca95bb523b015dee72c96480b68dfc1ce6a389af87a1a0c9f1557763a205d2c09b632c4b349a068b8f9b4855cf23be9b4574d7c6185b5119ee4bab9ea076b6c3a3c8b65bbbbd87907e20ad73e262a8c054e372f6db29f36c070040882e27c8632c9667f27fd5901a60986a7a3eaf3a83f809188509a58149144f08c32db39e6ecbd856b30d8d2416fc6f6de9f00cc2ae4d3f3a0b2c9fc3cbf2cc92931acf7f23af31aaed79f7b83a0a11d0f43a763e21eb41eab0e67b98b301e967d7cf1963dba78342eedc651cdfbe3e0b7dc54a27a4660dd48b7761",
  "updated_by": "postgres_only",
  "version": "v1",
  "network_token_requestor_reference_id": null,
  "network_token_locker_id": null,
  "network_token_payment_method_data": null,
  "external_vault_source": null,
  "vault_type": "internal",
  "created_by": null,
  "last_modified_by": null
}
  • Save Card flow, and generate network token during card payment method data when setup future usage is on_Session
Screenshot 2025-12-04 at 11 33 03 PM
  • Save Network token data when network token is passed as payment method data in request when setup future usage is on_Session
Screenshot 2025-12-04 at 11 52 50 PM
  • Pre network tokenization
Screenshot 2025-12-05 at 12 02 08 AM
  • Save Card flow, and generate network token during card payment method data when setup future usage is off_Session
Screenshot 2025-12-05 at 12 05 26 AM
  • Save Network token data when network token is passed as payment method data in request when setup future usage is off_Session
Screenshot 2025-12-05 at 12 06 27 AM
  • Repeat CIT
Screenshot 2025-12-10 at 2 43 51 PM

Checklist

  • I formatted the code cargo +nightly fmt --all
  • I addressed lints thrown by cargo clippy
  • I reviewed the submitted code
  • I added unit tests for my changes where possible

@ImSagnik007 ImSagnik007 requested review from a team as code owners October 24, 2025 08:34
@semanticdiff-com
Copy link

semanticdiff-com bot commented Oct 24, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs  84% smaller
  crates/router/src/core/payout_link.rs  83% smaller
  crates/connector_configs/src/transformer.rs  83% smaller
  crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs  82% smaller
  crates/hyperswitch_connectors/src/connectors/adyen.rs  80% smaller
  crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs  78% smaller
  crates/hyperswitch_connectors/src/connectors/klarna.rs  78% smaller
  crates/router/src/core/payments/payment_methods.rs  77% smaller
  crates/hyperswitch_connectors/src/connectors/noon/transformers.rs  76% smaller
  crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs  76% smaller
  crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs  76% smaller
  crates/router/src/core/payments.rs  76% smaller
  crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/worldline/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/fiserv/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/nmi/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/braintree/transformers.rs  75% smaller
  crates/hyperswitch_connectors/src/connectors/archipel/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/bambora/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/billwerk/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/boku/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/cryptopay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/datatrans/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/dlocal/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/facilitapay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/forte/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/gocardless/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/helcim/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/iatapay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/itaubank/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/mifinity/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/opayo/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/placetopay/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/powertranz/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/square/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/stax/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/tsys/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/volt/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/zen/transformers.rs  74% smaller
  crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs  73% smaller
  crates/router/src/core/payments/operations/payment_response.rs  70% smaller
  crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs  69% smaller
  crates/hyperswitch_connectors/src/connectors/payme/transformers.rs  68% smaller
  crates/kgraph_utils/src/transformers.rs  67% smaller
  crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs  65% smaller
  crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs  65% smaller
  crates/hyperswitch_connectors/src/connectors/nexixpay/transformers.rs  63% smaller
  crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs  60% smaller
  crates/euclid/src/frontend/dir/transformers.rs  58% smaller
  crates/common_enums/src/enums.rs  57% smaller
  crates/router/src/core/payments/helpers.rs  53% smaller
  crates/hyperswitch_domain_models/src/router_data.rs  45% smaller
  crates/hyperswitch_connectors/src/connectors/aci/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/trustpay/transformers.rs  43% smaller
  crates/router/src/connector/utils.rs  26% smaller
  crates/hyperswitch_connectors/src/connectors/breadpay/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/celero/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/jpmorgan/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/mollie/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/tesouro/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/zsl/transformers.rs  18% smaller
  crates/hyperswitch_connectors/src/connectors/nordea/transformers.rs  17% smaller
  crates/hyperswitch_connectors/src/connectors/redsys/transformers.rs  17% smaller
  crates/openapi/src/openapi_v2.rs  12% smaller
  crates/openapi/src/openapi.rs  5% smaller
  crates/hyperswitch_domain_models/src/payment_method_data.rs  4% smaller
  crates/router/src/routes/payments.rs  4% smaller
  crates/api_models/src/payments.rs  4% smaller
  crates/api_models/src/mandates.rs  4% smaller
  api-reference/v2/openapi_spec_v2.json  3% smaller
  crates/router/src/types/payment_methods.rs  3% smaller
  api-reference/v1/openapi_spec_v1.json  3% smaller
  crates/api_models/src/routing.rs  0% smaller
  crates/cards/src/validate.rs  0% smaller
  crates/common_enums/src/transformers.rs  0% smaller
  crates/common_types/src/payments.rs  0% smaller
  crates/connector_configs/src/response_modifier.rs  0% smaller
  crates/euclid/src/dssa/graph.rs  0% smaller
  crates/euclid/src/frontend/ast/lowering.rs  0% smaller
  crates/euclid/src/frontend/dir.rs  0% smaller
  crates/euclid/src/frontend/dir/enums.rs  0% smaller
  crates/euclid/src/frontend/dir/lowering.rs  0% smaller
  crates/euclid_wasm/src/lib.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/peachpayments/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/connectors/unified_authentication_service/transformers.rs  0% smaller
  crates/hyperswitch_connectors/src/utils.rs  0% smaller
  crates/hyperswitch_domain_models/src/lib.rs  0% smaller
  crates/hyperswitch_domain_models/src/network_tokenization.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types/unified_authentication_service.rs  0% smaller
  crates/kgraph_utils/src/mca.rs  0% smaller
  crates/payment_methods/src/helpers.rs  0% smaller
  crates/router/src/core/payments/routing/utils.rs  0% smaller
  crates/router/src/core/unified_authentication_service/utils.rs Unsupported file format
  crates/router/src/routes/payments/helpers.rs  0% smaller
  crates/router/src/types/domain.rs  0% smaller
  crates/router/src/types/transformers.rs  0% smaller

@codecov
Copy link

codecov bot commented Oct 24, 2025

Codecov Report

❌ Patch coverage is 0.58480% with 340 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@d104ce9). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...perswitch_domain_models/src/payment_method_data.rs 0.00% 166 Missing ⚠️
crates/hyperswitch_connectors/src/utils.rs 0.00% 44 Missing ⚠️
crates/router/src/core/payments.rs 0.00% 33 Missing ⚠️
crates/api_models/src/payments.rs 0.00% 17 Missing ⚠️
crates/euclid/src/frontend/dir.rs 11.11% 8 Missing ⚠️
crates/kgraph_utils/src/transformers.rs 0.00% 8 Missing ⚠️
crates/cards/src/validate.rs 0.00% 6 Missing ⚠️
...h_connectors/src/connectors/stripe/transformers.rs 0.00% 6 Missing ⚠️
crates/router/src/core/payments/routing/utils.rs 0.00% 6 Missing ⚠️
crates/euclid/src/frontend/dir/lowering.rs 0.00% 5 Missing ⚠️
... and 20 more
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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@prasunna09
Copy link
Contributor

Can we have clear title and description?
changes done in the pr? this is not self-explanatory

@ImSagnik007
Copy link
Contributor Author

Can we have clear title and description? changes done in the pr? this is not self-explanatory

Can you check the solution doc, already attached in the description.

@prasunna09
Copy link
Contributor

did we test out the pre network tokenization and save card flow for this?
Please test all the flows that includes network tokenization.

@ImSagnik007
Copy link
Contributor Author

did we test out the pre network tokenization and save card flow for this? Please test all the flows that includes network tokenization.

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.

@prasunna09
Copy link
Contributor

did we test out the pre network tokenization and save card flow for this? Please test all the flows that includes network tokenization.

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.
here, it is mentioned Network Token Payment Method , but in changes, it has network transaction id and network token?

Can we please follow the commit guidelines -
https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md#commits

@ImSagnik007 ImSagnik007 changed the title feat(core): Network Token Payment Method feat(core): [Network Token] Passing Network Token in payments request Nov 10, 2025
@ImSagnik007 ImSagnik007 force-pushed the network_token_pm branch 2 times, most recently from cab4658 to db87d03 Compare November 10, 2025 10:55
@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Nov 10, 2025
@ImSagnik007
Copy link
Contributor Author

ImSagnik007 commented Nov 10, 2025

did we test out the pre network tokenization and save card flow for this? Please test all the flows that includes network tokenization.

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. here, it is mentioned Network Token Payment Method , but in changes, it has network transaction id and network token?

Can we please follow the commit guidelines - https://github.com/juspay/hyperswitch/blob/main/docs/CONTRIBUTING.md#commits

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?

Copy link
Contributor

@prasunna09 prasunna09 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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


/// The token's network
#[schema(value_type = Option<CardNetwork>, example = "Visa")]
pub network: Option<api_enums::CardNetwork>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub network: Option<api_enums::CardNetwork>,
pub card_network: Option<api_enums::CardNetwork>,

pub struct NetworkTransactionIdAndNetworkTokenDetails {
/// The Network Token
#[schema(value_type = String, example = "4242424242424242")]
pub network_token: cards::CardNumber,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use the network token type instead of cardnumber?

pub struct NetworkTokenData {
/// The network token
#[schema(value_type = String, example = "4242424242424242")]
pub network_token: CardNumber,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use network token type instead of card number


/// The token cryptogram
#[schema(value_type = Option<String>)]
pub token_cryptogram: Option<Secret<String>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    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


/// The token cryptogram
#[schema(value_type = Option<String>)]
pub token_cryptogram: Option<Secret<String>>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is cryptogram optional?
without cryptogram, network token cannot be processed

Comment on lines +8462 to +8472
dt.network_token
.peek()
.clone()
.chars()
.rev()
.take(4)
.collect::<String>()
.chars()
.rev()
.collect::<String>()
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we write get method for this


#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize, Default)]
pub struct NetworkTokenDetailsForNetworkTransactionId {
pub network_token: cards::CardNumber,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use network token type

@prasunna09
Copy link
Contributor

also can we fix the clippy for both v1 and v2?

@prasunna09 prasunna09 added the T-Core For Work done by the core team label Nov 10, 2025
@ImSagnik007 ImSagnik007 force-pushed the network_token_pm branch 4 times, most recently from 3d3fa06 to fb1a943 Compare November 18, 2025 13:05
Comment on lines +3229 to +3265
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>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use card info table to update card network in core?

or will it always be empty if not passed in the request?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be empty of not passed in the request

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>>,
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add respective doc comments

Comment on lines +237 to +239
api_models::enums::PaymentMethod::NetworkToken => {
// NetworkToken is not yet supported in the response modifier
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this used?

and why is it empty for network token? is it intentional?

Comment on lines +201 to +218
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,
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are we having cybersource support in this pr?
Can we now put it under not implemented, and raise sepperate pr for this?

Comment on lines +7027 to +7053
#[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)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need v1 and v2 if both impl are same??

Comment on lines +7056 to +7063
fn get_network_token(&self) -> NetworkTokenNumber {
self.network_token.clone()
}

#[cfg(feature = "v2")]
fn get_network_token(&self) -> NetworkTokenNumber {
self.network_token.clone()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment on lines +7086 to +7093
fn get_cryptogram(&self) -> Option<Secret<String>> {
None
}

#[cfg(feature = "v2")]
fn get_cryptogram(&self) -> Option<Secret<String>> {
None
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this none?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NetworkTokenDetailsWithNTI doesn't have the field cryptogram

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get_cryptogram can be used in repeat CIT right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since it is a mit flow, cryptogram is not present here.

pub type NetworkTokenNumber = CardNumber;

#[cfg(feature = "v2")]
pub type NetworkTokenNumber = NetworkToken;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have deprecated, why are having v1 and v2 in utils?

}
}

#[cfg(feature = "v1")]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this should be under v1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +8705 to +8726
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(_) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets have micro pr for api changes, core changes, and connector changes seperately

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed the connector related changes, network token and ntid related changes should be in this PR for e2e flow for normal and cit/mits.

prasunna09
prasunna09 previously approved these changes Dec 12, 2025
Comment on lines +1024 to +1028
if cryptogram.trim().is_empty() {
Err(report!(errors::ApiErrorResponse::PreconditionFailed {
message: "Invalid token_cryptogram".to_string()
}))?
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can use when method from utils

ShankarSinghC
ShankarSinghC previously approved these changes Dec 15, 2025
AkshayaFoiger
AkshayaFoiger previously approved these changes Dec 15, 2025
Sakilmostak
Sakilmostak previously approved these changes Dec 15, 2025
@bernard-eugine bernard-eugine added this pull request to the merge queue Dec 18, 2025
Merged via the queue into main with commit 4eeb5c6 Dec 18, 2025
28 of 31 checks passed
@bernard-eugine bernard-eugine deleted the network_token_pm branch December 18, 2025 08:32
pixincreate added a commit that referenced this pull request Dec 22, 2025
…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)
pixincreate added a commit that referenced this pull request Dec 22, 2025
…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)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

M-api-contract-changes Metadata: This PR involves API contract changes T-Core For Work done by the core team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants