Skip to content

feat(injector): injector request formation changes#9306

Merged
likhinbopanna merged 20 commits intomainfrom
injector_changes
Sep 11, 2025
Merged

feat(injector): injector request formation changes#9306
likhinbopanna merged 20 commits intomainfrom
injector_changes

Conversation

@su-shivanshmathur
Copy link
Contributor

@su-shivanshmathur su-shivanshmathur commented Sep 8, 2025

Type of Change

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

Description

Request creation changes for injector to be used InjectorRequest struct creation.

impl InjectorRequest {
        pub fn new()
}

Also change the response type

pub struct InjectorResponse {
        /// HTTP status code from the connector response
        pub status_code: u16,
        /// Response headers from the connector (optional)
        pub headers: Option<HashMap<String, String>>,
        /// Response body from the connector
        pub response: serde_json::Value,
    }

Additional Changes

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

Motivation and Context

Making injector request and response more responsive and detailed from HTTP request

How did you test it?

Test cases which are present in the crate

  1. Create a profile
curl --location 'http://localhost:8080/v2/profiles' \
--header 'x-merchant-id: MERCHANT_ID' \
--header 'Authorization: admin-api-key=ADMIN_API_KEY' \

--header 'Content-Type: application/json' \
--header 'api-key: ADMIN_API_KEY' \
--data-raw '{
    "profile_name": "business_test_5",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true
    },
    "metadata": null,
    "order_fulfillment_time": 900,
    "order_fulfillment_time_origin": "create",
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "collect_shipping_details_from_wallet_connector_if_required": false,
    "collect_billing_details_from_wallet_connector_if_required": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": false,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null
}'

Response

{
    "merchant_id": "cloth_seller_TEP9F7yYvhHwegRK39Nf",
    "id": "PROFILE_ID",
    "profile_name": "business_test_7",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "NFgBM5rvXEI0wLgqQvT3oEgFPqj5w3Ncupj3bEA5MYanoJwq1oIycDh0jWEHGuUx",
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true,
        "payment_statuses_enabled": null,
        "refund_statuses_enabled": null,
        "payout_statuses_enabled": null
    },
    "metadata": null,
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "extended_card_info_config": null,
    "collect_shipping_details_from_wallet_connector_if_required": false,
    "collect_billing_details_from_wallet_connector_if_required": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": false,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null,
    "order_fulfillment_time": 900,
    "order_fulfillment_time_origin": "create",
    "tax_connector_id": null,
    "is_tax_connector_enabled": false,
    "is_network_tokenization_enabled": false,
    "should_collect_cvv_during_payment": null,
    "is_click_to_pay_enabled": false,
    "authentication_product_ids": null,
    "card_testing_guard_config": {
        "card_ip_blocking_status": "disabled",
        "card_ip_blocking_threshold": 3,
        "guest_user_card_blocking_status": "disabled",
        "guest_user_card_blocking_threshold": 10,
        "customer_id_blocking_status": "disabled",
        "customer_id_blocking_threshold": 5,
        "card_testing_guard_expiry": 3600
    },
    "is_clear_pan_retries_enabled": false,
    "is_debit_routing_enabled": false,
    "merchant_business_country": null,
    "is_iframe_redirection_enabled": null,
    "is_external_vault_enabled": null,
    "external_vault_connector_details": null,
    "merchant_category_code": null,
    "merchant_country_code": null,
    "split_txns_enabled": "skip"
}
  1. Create a connector account for vault processor (VGS)
curl --location 'http://localhost:8080/v2/connector-accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-merchant-id: MERCHANT_ID' \
--header 'x-profile-id: PROFILE_ID' \
--header 'x-feature: hyperswitch-custom-v2' \
--header 'Authorization: admin-api-key=ADMIN_API_KEY' \
--header 'api-key: ADMIN_API_KEY' \
--data-raw '{
"connector_type": "vault_processor",
    "connector_name": "vgs",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "{CONNECTOR_API_KEY}",
        "key1": "{CONNECTOR_KEY1}",
        "api_secret": "{CONNECTOR_API_SECRET}"
    },
    "frm_configs": null,
    "connector_webhook_details": {
        "merchant_secret": ""
    },
    "profile_id": "PROFILE_ID",
    "metadata": {
        "proxy_url": "{VAULT_URL}",
        "certificate": "{BASE64_ENCODED_CERTIFICATE}"
    }
}'

Response

{
    "connector_type": "vault_processor",
    "connector_name": "vgs",
    "connector_label": "vgs_business_test_7",
    "id": "MERCHANT_CONNECTOR_ACCOUNT_ID",
    "profile_id": "PROFILE_ID",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "US********************mi",
        "key1": "86********************************26",
        "api_secret": "tn*******lr"
    },
    "payment_methods_enabled": null,
    "connector_webhook_details": {
        "merchant_secret": "",
        "additional_secret": null
    },
    "metadata": {
        "proxy_url": "https://vault.verygoodproxy.com",
        "certificate": "CERTIFICATE_BASE64_ENCODED"
    },
    "disabled": false,
    "frm_configs": null,
    "applepay_verified_domains": null,
    "pm_auth_config": null,
    "status": "active",
    "additional_merchant_data": null,
    "connector_wallets_details": null,
    "feature_metadata": null
}
  1. Create a connector account for payment processor (Adyen)
curl --location 'http://localhost:8080/v2/connector-accounts' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'x-merchant-id: MERCHANT_ID' \
--header 'x-profile-id: PROFILE_ID' \
--header 'Authorization: admin-api-key=ADMIN_API_KEY' \
--header 'api-key: ADMIN_API_KEY' \
--data '{
    "connector_type": "payment_processor",
    "connector_name": "adyen",
     "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "{CONNECTOR_API_KEY}",
        "key1": "{CONNECTOR_KEY1}",
        "api_secret":"{CONNECTOR_API_SECRET}"
    },
    "payment_methods_enabled": [
        {
            "payment_method_type": "card",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "credit",
                    "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
                },
                {
                    "payment_method_subtype": "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
                }
            ]
        },
        {
            "payment_method_type": "wallet",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "google_pay",
                    "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_subtype": "apple_pay",
                    "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_subtype": "we_chat_pay",
                    "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_subtype": "ali_pay",
                    "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_subtype": "paypal",
                    "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_subtype": "mb_way",
                    "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_type": "pay_later",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "klarna",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "affirm",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "afterpay_clearpay",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "walley",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
        
        
    ],
    "metadata": {
        "status_url": "https://example.com/status",
        "account_name": "transaction_processing",
        "pricing_type": "fixed_price",
        "acquirer_bin": "438309",
        "acquirer_merchant_id": "00002000000"
    },
    "frm_configs": null,
    "connector_webhook_details": {
        "merchant_secret": ""
    },
    "profile_id": "PROFILE_ID"
}'

Response

{
    "connector_type": "payment_processor",
    "connector_name": "adyen",
    "connector_label": "adyen_business_test_7",
    "id": "MERCHANT_CONNECTOR_ACCOUNT_ID",
    "profile_id": "PROFILE_ID",
    "connector_account_details": {
        "auth_type": "SignatureKey",
        "api_key": "US********************mi",
        "key1": "Ju*******************************OM",
        "api_secret": "tn*******"
    },
    "payment_methods_enabled": [
        {
            "payment_method_type": "card",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "credit",
                    "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
                },
                {
                    "payment_method_subtype": "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
                }
            ]
        },
        {
            "payment_method_type": "wallet",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "google_pay",
                    "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_subtype": "apple_pay",
                    "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_subtype": "we_chat_pay",
                    "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_subtype": "ali_pay",
                    "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_subtype": "paypal",
                    "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_subtype": "mb_way",
                    "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_type": "pay_later",
            "payment_method_subtypes": [
                {
                    "payment_method_subtype": "klarna",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "affirm",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "afterpay_clearpay",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                },
                {
                    "payment_method_subtype": "walley",
                    "payment_experience": "redirect_to_url",
                    "card_networks": null,
                    "accepted_currencies": null,
                    "accepted_countries": null,
                    "minimum_amount": -1,
                    "maximum_amount": 68607706,
                    "recurring_enabled": true,
                    "installment_payment_enabled": true
                }
            ]
        }
    ],
    "connector_webhook_details": {
        "merchant_secret": "",
        "additional_secret": null
    },
    "metadata": {
        "status_url": "https://2753-2401-4900-1cb8-2ff9-24dd-1ccf-ed12-b464.in.ngrok.io/webhooks/merchant_1678699058/globalpay",
        "account_name": "transaction_processing",
        "acquirer_bin": "438309",
        "pricing_type": "fixed_price",
        "acquirer_merchant_id": "00002000000"
    },
    "disabled": false,
    "frm_configs": null,
    "applepay_verified_domains": null,
    "pm_auth_config": null,
    "status": "active",
    "additional_merchant_data": null,
    "connector_wallets_details": null,
    "feature_metadata": null
}
  1. Create an API key for the profile
curl --location 'http://localhost:8080/v2/api-keys' \
--header 'x-merchant-id: MERCHANT_ID' \
--header 'Authorization: admin-api-key=ADMIN_API_KEY' \
--header 'Content-Type: application/json' \
--header 'api-key: ADMIN_API_KEY' \
--data '{
    "name": "My Api Key",
    "expiration": "never"
}'

Response

{
    "key_id": "KEY_ID",
    "merchant_id": "MERCHANT_ID",
    "name": "My Api Key",
    "description": null,
    "api_key": "API_KEY",
    "created": "2025-09-11T10:14:53.929Z",
    "expiration": "never"
}
  1. Create a customer
curl --location 'http://localhost:8080/v2/customers' \
--header 'x-profile-id: PROFILE_ID' \
--header 'Authorization: api-key=API_KEY' \
--header 'Content-Type: application/json' \
--header 'api-key: API_KEY' \
--data-raw '{   
    "merchant_reference_id": "customer_1757584966",
    "name": "John Doe",
    "email": "guest@example.com",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "First customer",
    "default_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"
    },
    "default_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"
    },
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    }
}'

Response

{
    "id": "12345_cus_01993844c6c47dc39f528073a92ad278",
    "merchant_reference_id": "customer_1757585655",
    "connector_customer_ids": null,
    "name": "John Doe",
    "email": "guest@example.com",
    "phone": "999999999",
    "phone_country_code": "+65",
    "description": "First customer",
    "default_billing_address": null,
    "default_shipping_address": null,
    "created_at": "2025-09-11T10:14:15.493Z",
    "metadata": {
        "udf1": "value1",
        "new_customer": "true",
        "login_date": "2019-09-10T10:11:12Z"
    },
    "default_payment_method_id": null,
    "tax_registration_id": null
}
  1. Update the profile to add external vault details
curl -v --location --request PUT 'http://localhost:8080/v2/profiles/PROFILE_ID' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: PROFILE_ID' \
--header 'Authorization: admin-api-key=ADMIN_API_KEY' \
--header 'x-merchant-id: MERCHANT_ID' \
--header 'x-tenant: public' \
--data-raw '{
    "profile_name": "Update",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true
    },
    "metadata": null,
    "order_fulfillment_time": 900,
    "order_fulfillment_time_origin": "create",
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "collect_shipping_details_from_wallet_connector_if_required": false,
    "collect_billing_details_from_wallet_connector_if_required": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": false,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null,
    "is_external_vault_enabled": true,
    "external_vault_connector_details": {
        
        "vault_connector_id": "MERCHANT_CONNECTOR_ACCOUNT",
        "vault_sdk": "vgs_sdk"
    }
}'

Response

{
    "merchant_id": "{MERCHANT_ID}",
    "id": "PROFILE_ID",
    "profile_name": "Update",
    "return_url": "https://google.com/success",
    "enable_payment_response_hash": true,
    "payment_response_hash_key": "doVXhW8TEtgpZNZgrytLAnIuegoyApXlKwnXMM7nIe3tWKbRwlZ14CiNWRaThnQX",
    "redirect_to_merchant_with_http_post": false,
    "webhook_details": {
        "webhook_version": "1.0.1",
        "webhook_username": "ekart_retail",
        "webhook_password": "password_ekart@123",
        "webhook_url": "https://webhook.site",
        "payment_created_enabled": true,
        "payment_succeeded_enabled": true,
        "payment_failed_enabled": true,
        "payment_statuses_enabled": null,
        "refund_statuses_enabled": null,
        "payout_statuses_enabled": null
    },
    "metadata": null,
    "applepay_verified_domains": null,
    "session_expiry": 900,
    "payment_link_config": null,
    "authentication_connector_details": null,
    "use_billing_as_payment_method_billing": true,
    "extended_card_info_config": null,
    "collect_shipping_details_from_wallet_connector_if_required": false,
    "collect_billing_details_from_wallet_connector_if_required": false,
    "always_collect_shipping_details_from_wallet_connector": false,
    "always_collect_billing_details_from_wallet_connector": false,
    "is_connector_agnostic_mit_enabled": false,
    "payout_link_config": null,
    "outgoing_webhook_custom_http_headers": null,
    "order_fulfillment_time": 900,
    "order_fulfillment_time_origin": "create",
    "tax_connector_id": null,
    "is_tax_connector_enabled": false,
    "is_network_tokenization_enabled": false,
    "should_collect_cvv_during_payment": null,
    "is_click_to_pay_enabled": false,
    "authentication_product_ids": null,
    "card_testing_guard_config": {
        "card_ip_blocking_status": "disabled",
        "card_ip_blocking_threshold": 3,
        "guest_user_card_blocking_status": "disabled",
        "guest_user_card_blocking_threshold": 10,
        "customer_id_blocking_status": "disabled",
        "customer_id_blocking_threshold": 5,
        "card_testing_guard_expiry": 3600
    },
    "is_clear_pan_retries_enabled": false,
    "is_debit_routing_enabled": false,
    "merchant_business_country": null,
    "is_iframe_redirection_enabled": null,
    "is_external_vault_enabled": true,
    "external_vault_connector_details": {
        "vault_connector_id": "MERCHANT_CONNECTOR_ACCOUNT",
        "vault_sdk": "vgs_sdk"
    },
    "merchant_category_code": null,
    "merchant_country_code": null,
    "split_txns_enabled": "skip"
}
  1. Create a payment intent with card details using external vault
curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: PROFILE_ID' \
--header 'Authorization: api-key=API_KEY' \

--header 'x-tenant: public' \
--header 'api-key: API_KEY' \
--data-raw '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "customer_id": "CUSTOMER_ID",
    "capture_method":"manual",
    "authentication_type": "no_three_ds",
    "shipping": {
        "address": {
            "first_name": "John",
            "last_name": "Dough",
            "city": "Karwar",
            "zip": "581301",
            "state": "Karnataka",
            "country": "NL"
        },
        "email": "example@example.com"
    },
    "metadata":{
        "udf":"test"
    },
    "merchant_reference_id":"NOPA",
    "billing": {
        "address": {
            "city": "test",
            "country": "NL",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "SE",
            "first_name": "Sakil",
            "last_name": "Mostak"
        },
        "phone": {
            "number": "1234567890",
            "country_code": "+1"
        },
        "email": "guest@example.com"
    }
}'

Response

{
    "id": "12345_pay_019914bad4b97b51a5784378d30b65e2",
    "status": "requires_payment_method",
    "amount_details": {
        "order_amount": 100,
        "currency": "USD",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null
    },
    "client_secret": "cs_019914bad58a7d419202971c85f52e78",
    "profile_id": "pro_zxVxleDz6pBK70pPhvHw",
    "merchant_reference_id": "NOPA",
    "routing_algorithm_id": null,
    "capture_method": "manual",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": "test",
            "country": "NL",
            "line1": "here is some \n there is some \n none is some? \n ",
            "line2": "there",
            "line3": "anywhere",
            "zip": "560095",
            "state": "SE",
            "first_name": "Sakil",
            "last_name": "Mostak",
            "origin_zip": null
        },
        "phone": {
            "number": "1234567890",
            "country_code": "+1"
        },
        "email": "guest@example.com"
    },
    "shipping": {
        "address": {
            "city": "Karwar",
            "country": "NL",
            "line1": null,
            "line2": null,
            "line3": null,
            "zip": "581301",
            "state": "Karnataka",
            "first_name": "John",
            "last_name": "Dough",
            "origin_zip": null
        },
        "phone": null,
        "email": "example@example.com"
    },
    "customer_id": "CUSTOMER_ID",
    "customer_present": "present",
    "description": null,
    "return_url": null,
    "setup_future_usage": "on_session",
    "apply_mit_exemption": "Skip",
    "statement_descriptor": null,
    "order_details": null,
    "allowed_payment_method_types": null,
    "metadata": {
        "udf": "test"
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "false",
    "split_txns_enabled": "skip",
    "expires_on": "2025-09-04T12:51:52.734Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip",
    "payment_type": "normal"
}
  1. Confirm the payment intent using card details and vault data
curl --location 'http://localhost:8080/v2/payments/12345_pay_019914bad4b97b51a5784378d30b65e2/confirm-intent/external-vault-proxy' \
--header 'x-client-secret: CLIENT_SECRET' \
--header 'x-profile-id: PROFILE_ID' \
--header 'Authorization: api-key=API_KEY' \
--header 'Content-Type: application/json' \
--header 'api-key: API_KEY' \
--data '{
  "payment_method_type": "card",
  "payment_method_subtype": "debit",
  "payment_method_data": {
    "vault_data_card": {
      "card_number": "4166679492386746",
      "card_exp_month": "03",
      "card_exp_year": "2030",
      "card_cvc": "tok_sandbox_hmUN1L4M6ds1GQG62QmT8T",
      "bin_number": "42424",
      "last_four": "4242"
    }
  }
}'

Response

{
    "id": "12345_pay_019914bad4b97b51a5784378d30b65e2",
    "status": "succeeded",
    "amount": {
        "order_amount": 100,
        "currency": "USD",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null,
        "net_amount": 100,
        "amount_to_capture": null,
        "amount_capturable": 0,
        "amount_captured": 100
    },
    "customer_id": "CUSTOMER_ID",
    "connector": "adyen",
    "created": "2025-09-04T12:36:52.734Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "connector_transaction_id": "Z2FDRSJ53HKV5CV5",
    "connector_reference_id": "NOPA",
    "merchant_connector_id": "mca_DJWBJR6rTI5PdoJBWhov",
    "browser_info": null,
    "error": {
        "code": "CONNECTOR_ERROR",
        "message": "Failed to deserialize connector response",
        "unified_code": null,
        "unified_message": null,
        "network_advice_code": null,
        "network_decline_code": null,
        "network_error_message": null
    },
    "shipping": null,
    "billing": null,
    "attempts": null,
    "connector_token_details": null,
    "payment_method_id": null,
    "next_action": null,
    "return_url": "https://google.com/success",
    "authentication_type": "no_three_ds",
    "authentication_type_applied": "no_three_ds",
    "is_iframe_redirection_enabled": null,
    "merchant_reference_id": "NOPA",
    "raw_connector_response": null,
    "feature_metadata": null
}

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

@su-shivanshmathur su-shivanshmathur requested a review from a team as a code owner September 8, 2025 20:45
@semanticdiff-com
Copy link

semanticdiff-com bot commented Sep 8, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/injector/src/types.rs  13% smaller
  crates/injector/src/injector.rs  11% smaller
  crates/injector/src/consts.rs  0% smaller
  crates/injector/src/lib.rs  0% smaller
  crates/injector/src/vault_metadata.rs  0% smaller

@su-shivanshmathur su-shivanshmathur linked an issue Sep 8, 2025 that may be closed by this pull request
2 tasks
Comment on lines +109 to +112
let cert = reqwest::Certificate::from_pem(pem.as_bytes()).map_err(|e| {
logger::error!("Failed to parse CA certificate PEM block: {}", e);
error_stack::Report::new(InjectorError::HttpRequestFailed)
})?;
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
let cert = reqwest::Certificate::from_pem(pem.as_bytes()).map_err(|e| {
logger::error!("Failed to parse CA certificate PEM block: {}", e);
error_stack::Report::new(InjectorError::HttpRequestFailed)
})?;
let cert = reqwest::Certificate::from_pem(pem.as_bytes()).change_context(error_stack::Report::new(InjectorError::HttpRequestFailed))
.inspect(|e| logger::error!("Failed to parse CA certificate PEM block: {}", e);)?;

.build()
.change_context(HttpClientError::ClientConstructionFailed)
.attach_printable("Failed to construct client with CA certificate");
return client_builder.use_rustls_tls().build().map_err(|e| {
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

.attach_printable(
"Failed to construct client with certificate and certificate key",
);
.map_err(|e| {
Copy link
Contributor

Choose a reason for hiding this comment

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

change_context

proxy_config: &Proxy,
) -> error_stack::Result<reqwest::Client, InjectorError> {
let client_builder = get_client_builder(proxy_config)?;
client_builder.build().map_err(|e| {
Copy link
Contributor

Choose a reason for hiding this comment

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

change_context

);

let request = request_builder.build();
let mut request = request_builder.build();
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of building a mutable request, populate all required fields in builder itself and call .build() at the end

None
} else {
let mut headers_map = HashMap::new();
for (name, value) in header_map.iter() {
Copy link
Contributor

Choose a reason for hiding this comment

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

use iter().map()

pub max_response_size: Option<usize>,
}
/// External vault metadata processing module
pub mod vault_metadata {
Copy link
Contributor

Choose a reason for hiding this comment

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

modules can be a separate files

hrithikesh026
hrithikesh026 previously approved these changes Sep 9, 2025
hrithikesh026
hrithikesh026 previously approved these changes Sep 9, 2025
Comment on lines +10 to +11
const BASE64_ENGINE: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD;
pub const EXTERNAL_VAULT_METADATA_HEADER: &str = "x-external-vault-metadata";
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: move them to a common consts file

.attach_printable(
"Failed to construct client with certificate and certificate key",
);
.change_context(InjectorError::HttpRequestFailed)
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 unify the client builder to remove early returns?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

based on the condition only building the builder, otherwise need to create a mutable reference to the builder

hrithikesh026
hrithikesh026 previously approved these changes Sep 10, 2025
Sakilmostak
Sakilmostak previously approved these changes Sep 10, 2025
@hyperswitch-bot hyperswitch-bot bot dismissed stale reviews from Sakilmostak and hrithikesh026 via 73b0e20 September 10, 2025 12:35
@likhinbopanna likhinbopanna added this pull request to the merge queue Sep 11, 2025
Merged via the queue into main with commit fabe82d Sep 11, 2025
33 of 37 checks passed
@likhinbopanna likhinbopanna deleted the injector_changes branch September 11, 2025 12:12
pixincreate added a commit that referenced this pull request Sep 11, 2025
…ee-ds

* 'main' of github.com:juspay/hyperswitch:
  feat(webhooks): Provide outgoing webhook support for revenue recovery (#9294)
  feat(connector): Add Peachpayments Template Code (#9363)
  feat(connector): [Paysafe] Implement card 3ds flow (#9305)
  feat(router): Add Connector changes for 3ds (v2) (#9117)
  feat(connector): [ADYEN] Add support to ideal Mandate Webhook (#9347)
  refactor(core): accept manual retry from profile  (#9302)
  fix(nuvei): nuvei 3ds fix + psync fix (#9279)
  fix(connector): [checkout] Add US Support for Apple Pay and Google Pay + Enhanced Checkout Response Data (#9356)
  fix(router): adding connector_customer_id for external vault proxy (#9263)
  feat(core): Add first_name and last_name as Secret<String> Types.  (#9326)
  feat(injector): injector request formation changes (#9306)
  fix(revenue-recovery): Update Redis TTL for customer locks after token selection (#9282)
  chore(version): 2025.09.11.0
  refactor(connector): [Paysafe] fix wasm (#9349)
  refactor(connector): rename RevenueRecoveryRecordBack as InvoiceRecordBack (#9321)
  feat(connector): [checkout] add support for MOTO payments (#9327)
  feat(connector): enhance ACI connector with comprehensive 3DS support - DRAFT (#8986)
  feat(core): [Retry] MIT Retries (#8628)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Payments V2 supporting External vault

4 participants