Skip to content

Conversation

@Anurag-05-prog
Copy link
Contributor

@Anurag-05-prog Anurag-05-prog commented Jan 18, 2025

Type of Change

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

Description

Added Amazon Pay connector using Amazon Pay Wallet for the US region.

Flow:

  1. In the Hyperswitch dashboard, when configuring the Amazon Pay connector, merchants are required to provide their API keys, Merchant ID, and Store ID. The Merchant ID and Store ID are specifically necessary for rendering the Amazon Pay SDK.

  2. During the payments-create API call, merchants must include the amount and currency (currently, only USD is supported). Additionally, the following fields can be provided:

    • order_tax_amount: Required only if tax is being applied to the bill.

    • shipping_cost: This value must match the amount specified in the default delivery_option. This validation is enforced in the backend.

    • delivery_options: Passed within the metadata field, this should be an array of objects. Each object must include:

      • id

      • price: An object containing amount and currency

      • shipping_method: An object containing shipping_method_name and shipping_method_code

      • is_default: A boolean indicating whether the option is the default. Exactly one delivery option must have is_default set to true, which will determine the applicable shipping cost.

  3. In the session_tokens API call, all required information for rendering the Amazon Pay SDK on the frontend is provided.

  4. The Amazon Pay SDK is rendered on the frontend. Upon successful checkout, the frontend returns a checkout_session_id via the confirm API call. This identifier is essential for making the Authorize call. Currently, only the automatic capture method is supported, meaning the capture process is performed within the same call.

Note:
This PR currently supports only the Automatic capture method. Therefore, invoking the authorization flow will move the payment to a terminal state.

Additional Changes

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

Motivation and Context

https://developer.amazon.com/docs/amazon-pay-api-v2/introduction.html

How did you test it?

Postman Test

Connector configuration with merchant account

Request:

curl --location --globoff 'http://localhost:8080/account/{{merchant_id}}/connectors' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{admin_api_key}}' \
--data '{
    "connector_type": "payment_processor",
    "connector_name": "amazonpay",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "Merchant'\''s Public Key here",
        "key1": "Merchant'\''s Private Key here"
    },
    "test_mode": true,
    "disabled": false,
    "payment_methods_enabled": [
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "amazon_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
                }
            ]
        }
    ],
    "connector_wallets_details": {
        "amazon_pay": {
            "merchant_id": "Merchant Id here",
            "store_id": "Store Id here"
        }
    },
    "metadata": {
        "city": "NY",
        "unit": "245"
    },
    "connector_webhook_details": {
        "merchant_secret": "MyWebhookSecret"
    },
    "business_country": "US",
    "business_label": "default"
}'

Response:

{
    "connector_type": "payment_processor",
    "connector_name": "amazonpay",
    "connector_label": "amazonpay_US_default",
    "merchant_connector_id": "mca_dzcaJz3OXpbsEUtmnRRB",
    "profile_id": "pro_KjH58F7Kk38DKamoARZo",
    "connector_account_details": {
        "auth_type": "BodyKey",
        "api_key": "SA****************************YL",
        "key1": "--*******************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************--"
    },
    "payment_methods_enabled": [
        {
            "payment_method": "wallet",
            "payment_method_types": [
                {
                    "payment_method_type": "amazon_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
                }
            ]
        }
    ],
    "connector_webhook_details": {
        "merchant_secret": "MyWebhookSecret",
        "additional_secret": null
    },
    "metadata": {
        "city": "NY",
        "unit": "245"
    },
    "test_mode": true,
    "disabled": false,
    "frm_configs": null,
    "business_country": "US",
    "business_label": "default",
    "business_sub_label": null,
    "applepay_verified_domains": null,
    "pm_auth_config": null,
    "status": "active",
    "additional_merchant_data": null,
    "connector_wallets_details": {
        "amazon_pay": {
            "merchant_id": "***",
            "store_id": "***"
        }
    }
}
Create Payment

Request:

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{admin_api_key}}' \
--data '
{
    "amount": 5044,
    "currency": "USD",
    "shipping_cost": 2000,
    "order_tax_amount": 1000,
    "confirm": false,
    "metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price":{
                    "amount": 2000,
                    "currency_code":"USD"
                },
                "shipping_method":{
                    "shipping_method_name":"standard-courier",
                    "shipping_method_code":"standard-courier"
                },
                "is_default":true    
            },
            {
                "id":"express-delivery",
                "price":{
                    "amount":5000,
                    "currency_code":"USD"
                },
                "shipping_method":{
                    "shipping_method_name":"express-courier",
                    "shipping_method_code":"express-courier"
                },
                "is_default":false 
            }
        ]
    },
    "shipping": {
        "address": {
            "line1": "10 Ditka Ave",
            "line2": "Suite 2500",
            "line3": null,
            "city": "Chicago",
            "state": "IL",
            "zip": "60602",
            "country": "US",
            "first_name": "Susie",
            "last_name": "Smith"
        },
        "phone": {
            "number": "8000000000"
        }
    }
}'

Response:

{
    "payment_id": "***",
    "merchant_id": "merchant_1738388546",
    "status": "requires_payment_method",
    "amount": 5044,
    "net_amount": 11044,
    "shipping_cost": 5000,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "***",
    "created": "2025-02-01T06:04:17.308Z",
    "currency": "USD",
    "customer_id": null,
    "customer": null,
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "Chicago",
            "country": "US",
            "line1": "10 Ditka Ave",
            "line2": "Suite 2500",
            "line3": null,
            "zip": "60602",
            "state": "IL",
            "first_name": "Susie",
            "last_name": "Smith"
        },
        "phone": {
            "number": "8000000000",
            "country_code": null
        },
        "email": null
    },
    "billing": null,
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": null,
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price": {
                    "amount": 2000,
                    "currency_code": "USD"
                },
                "is_default": true,
                "shipping_method": {
                    "shipping_method_code": "standard-courier",
                    "shipping_method_name": "standard-courier"
                }
            },
            {
                "id": "express-delivery",
                "price": {
                    "amount": 5000,
                    "currency_code": "USD"
                },
                "is_default": false,
                "shipping_method": {
                    "shipping_method_code": "express-courier",
                    "shipping_method_name": "express-courier"
                }
            }
        ]
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_gv8MXTZYhAFvCVPskAYY",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-01T06:19:17.308Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-01T06:04:17.329Z",
    "split_payments": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": 1000,
    "connector_mandate_id": null
}
Session Token

Request:

curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: {{publishable_key}}' \
--data '{
    "payment_id": "Payment Id here",
    "wallets": [],
    "client_secret": "Client Secret here"
}'

Response:

{
    "payment_id": "***",
    "client_secret": "***",
    "session_token": [
        {
            "wallet_name": "amazon_pay",
            "merchant_id": "***",
            "ledger_currency": "USD",
            "store_id": "***",
            "payment_intent": "AuthorizeWithCapture",
            "total_shipping_amount": "20.00",
            "total_tax_amount": "10.00",
            "total_base_amount": "50.44",
            "delivery_options": [
                {
                    "id": "standard-delivery",
                    "price": {
                        "amount": 2000,
                        "display_amount": "20.00",
                        "currency_code": "USD"
                    },
                    "shipping_method": {
                        "shipping_method_name": "standard-courier",
                        "shipping_method_code": "standard-courier"
                    },
                    "is_default": true
                },
                {
                    "id": "express-delivery",
                    "price": {
                        "amount": 5000,
                        "display_amount": "50.00",
                        "currency_code": "USD"
                    },
                    "shipping_method": {
                        "shipping_method_name": "express-courier",
                        "shipping_method_code": "express-courier"
                    },
                    "is_default": false
                }
            ]
        }
    ]
}

If any field within the metadata is missing, the session_token in the response will be empty.

Payments - Create (with missing field in metadata)

Request:

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{admin_api_key}}' \
--data '{
    "amount": 5044,
    "currency": "USD",
    "shipping_cost": 2000,
    "order_tax_amount": 1000,
    "confirm": false,
    "metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price":{
                    "amount": 2000,
                    "currency_code":"USD"
                },
                "shipping_method":{
                    "shipping_method_code":"standard-courier"
                },
                "is_default":true
            },
            {
                "id":"express-delivery",
                "price":{
                    "amount":5000,
                    "currency_code":"USD"
                },
                "shipping_method":{
                    "shipping_method_name":"express-courier",
                    "shipping_method_code":"express-courier"
                },
                "is_default":false
            }
        ]
    }
}'

Response:

{
    "payment_id": "****",
    "merchant_id": "****",
    "status": "requires_payment_method",
    "amount": 5044,
    "net_amount": 8044,
    "shipping_cost": 2000,
    "amount_capturable": 0,
    "amount_received": null,
    "connector": null,
    "client_secret": "***",
    "created": "2025-02-11T15:19:11.396Z",
    "currency": "USD",
    "customer_id": null,
    "customer": null,
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": null,
    "payment_method": null,
    "payment_method_data": null,
    "payment_token": null,
    "shipping": null,
    "billing": null,
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": null,
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": null,
    "payment_method_type": null,
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": null,
    "connector_transaction_id": null,
    "frm_message": null,
    "metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price": {
                    "amount": 2000,
                    "currency_code": "USD"
                },
                "is_default": true,
                "shipping_method": {
                    "shipping_method_code": "standard-courier"
                }
            },
            {
                "id": "express-delivery",
                "price": {
                    "amount": 5000,
                    "currency_code": "USD"
                },
                "is_default": false,
                "shipping_method": {
                    "shipping_method_code": "express-courier",
                    "shipping_method_name": "express-courier"
                }
            }
        ]
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "***",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": null,
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-11T15:34:11.396Z",
    "fingerprint": null,
    "browser_info": null,
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-11T15:19:11.418Z",
    "split_payments": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": 1000,
    "connector_mandate_id": null
}
Session Token (when metadata is passed with missing field in payments-create call)

Request:

curl --location 'http://localhost:8080/payments/session_tokens' \
--header 'Content-Type: application/json' \
--header 'api-key: {{publishable_key}}' \
--data '{
    "payment_id": "Payment_ID_Here",
    "wallets": [],
    "client_secret": "Client_Secret_Here"
}'

Response:

{
    "payment_id": "***",
    "client_secret": "***",
    "session_token": []
}
Payments - Confirm

Request:

curl --location 'http://localhost:8080/payments/{{payment_id}}/confirm' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{api_key}}' \
--data '{
    "capture_method": "automatic", 
    "shipping": {
        "address": {
            "line1": "10 Ditka Ave",
            "line2": "Suite 2500",
            "line3": null,
            "city": "Chicago",
            "state": "IL",
            "zip": "60602",
            "country": "US",
            "first_name": "Susie",
            "last_name": "Smith"
        },
        "phone": {
            "number": "800-000-0000"
        }
    },
    "payment_method": "wallet",
    "payment_method_type": "amazon_pay",
    "payment_experience": "invoke_sdk_client",
    "payment_method_data": {
        "wallet": {
            "amazon_pay": {
                "checkout_session_id": "Checkout Session Id here"
            }
        }
    }
}'

Response:

{
    "payment_id": "***",
    "merchant_id": "merchant_1738388546",
    "status": "succeeded",
    "amount": 5044,
    "net_amount": 11044,
    "shipping_cost": 5000,
    "amount_capturable": 0,
    "amount_received": 11044,
    "connector": "amazonpay",
    "client_secret": "***",
    "created": "2025-02-01T06:04:17.308Z",
    "currency": "USD",
    "customer_id": null,
    "customer": null,
    "description": null,
    "refunds": null,
    "disputes": null,
    "mandate_id": null,
    "mandate_data": null,
    "setup_future_usage": null,
    "off_session": null,
    "capture_on": null,
    "capture_method": "automatic",
    "payment_method": "wallet",
    "payment_method_data": {
        "wallet": {},
        "billing": null
    },
    "payment_token": null,
    "shipping": {
        "address": {
            "city": "Chicago",
            "country": "US",
            "line1": "10 Ditka Ave",
            "line2": "Suite 2500",
            "line3": null,
            "zip": "60602",
            "state": "IL",
            "first_name": "Susie",
            "last_name": "Smith"
        },
        "phone": {
            "number": "800-000-0000",
            "country_code": null
        },
        "email": null
    },
    "billing": null,
    "order_details": null,
    "email": null,
    "name": null,
    "phone": null,
    "return_url": null,
    "authentication_type": "no_three_ds",
    "statement_descriptor_name": null,
    "statement_descriptor_suffix": null,
    "next_action": null,
    "cancellation_reason": null,
    "error_code": null,
    "error_message": null,
    "unified_code": null,
    "unified_message": null,
    "payment_experience": "invoke_sdk_client",
    "payment_method_type": "amazon_pay",
    "connector_label": null,
    "business_country": null,
    "business_label": "default",
    "business_sub_label": null,
    "allowed_payment_method_types": null,
    "ephemeral_key": null,
    "manual_retry_allowed": false,
    "connector_transaction_id": "***",
    "frm_message": null,
    "metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price": {
                    "amount": "20.00",
                    "currency_code": "USD"
                },
                "is_default": true,
                "shipping_method": {
                    "shipping_method_code": "standard-courier",
                    "shipping_method_name": "standard-courier"
                }
            },
            {
                "id": "express-delivery",
                "price": {
                    "amount": "50",
                    "currency_code": "USD"
                },
                "is_default": false,
                "shipping_method": {
                    "shipping_method_code": "express-courier",
                    "shipping_method_name": "express-courier"
                }
            }
        ]
    },
    "connector_metadata": null,
    "feature_metadata": null,
    "reference_id": null,
    "payment_link": null,
    "profile_id": "pro_gv8MXTZYhAFvCVPskAYY",
    "surcharge_details": null,
    "attempt_count": 1,
    "merchant_decision": null,
    "merchant_connector_id": "mca_GaSYTsJoc2VB9jkwD9Ag",
    "incremental_authorization_allowed": null,
    "authorization_count": null,
    "incremental_authorizations": null,
    "external_authentication_details": null,
    "external_3ds_authentication_attempted": false,
    "expires_on": "2025-02-01T06:19:17.308Z",
    "fingerprint": null,
    "browser_info": {
        "os_type": null,
        "language": null,
        "time_zone": null,
        "ip_address": "::1",
        "os_version": null,
        "user_agent": null,
        "color_depth": null,
        "device_model": null,
        "java_enabled": null,
        "screen_width": null,
        "accept_header": null,
        "screen_height": null,
        "accept_language": "en",
        "java_script_enabled": null
    },
    "payment_method_id": null,
    "payment_method_status": null,
    "updated": "2025-02-01T06:12:41.541Z",
    "split_payments": null,
    "frm_metadata": null,
    "merchant_order_reference_id": null,
    "order_tax_amount": 1000,
    "connector_mandate_id": null
}
Refunds - Create

Request:

curl --location 'http://localhost:8080/refunds' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: {{api_key}}' \
--data '{
    "payment_id": "{{payment_id}}",
    "amount": 11044,
    "reason": "Customer returned product",
    "refund_type": "instant" 
}'

Response:

{
    "refund_id": "***",
    "payment_id": "***",
    "amount": 11044,
    "currency": "USD",
    "status": "pending",
    "reason": "Customer returned product",
    "metadata": null,
    "error_message": null,
    "error_code": null,
    "unified_code": null,
    "unified_message": null,
    "created_at": "2025-02-01T06:16:01.318Z",
    "updated_at": "2025-02-01T06:16:03.084Z",
    "connector": "amazonpay",
    "profile_id": "pro_gv8MXTZYhAFvCVPskAYY",
    "merchant_connector_id": "mca_GaSYTsJoc2VB9jkwD9Ag",
    "split_refunds": null
}
Refunds - Retrieve

Request:

curl --location 'http://localhost:8080/refunds/{{refund_id}}' \
--header 'Accept: application/json' \
--header 'api-key: {{api_key}}'

Response:

{
    "refund_id": "***",
    "payment_id": "***",
    "amount": 11044,
    "currency": "USD",
    "status": "succeeded",
    "reason": "Customer returned product",
    "metadata": null,
    "error_message": null,
    "error_code": null,
    "unified_code": null,
    "unified_message": null,
    "created_at": "2025-02-01T06:16:01.318Z",
    "updated_at": "2025-02-01T06:18:16.267Z",
    "connector": "amazonpay",
    "profile_id": "pro_gv8MXTZYhAFvCVPskAYY",
    "merchant_connector_id": "mca_GaSYTsJoc2VB9jkwD9Ag",
    "split_refunds": null
}
Feature API

Request:

curl --location 'http://localhost:8080/feature_matrix' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: ***'

Response:

{
    "connector_count": 1,
    "connectors": [
        {
            "name": "AMAZONPAY",
            "description": "Amazon Pay is an Alternative Payment Method (APM) connector that allows merchants to accept payments using customers' stored Amazon account details, providing a seamless checkout experience.",
            "category": "alternative_payment_method",
            "supported_payment_methods": [
                {
                    "payment_method": "wallet",
                    "payment_method_type": "amazon_pay",
                    "mandates": "not_supported",
                    "refunds": "supported",
                    "supported_capture_methods": [
                        "automatic"
                    ],
                    "supported_countries": [
                        "US"
                    ],
                    "supported_currencies": [
                        "USD"
                    ]
                }
            ],
            "supported_webhook_flows": []
        },
    ]
}

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

@Anurag-05-prog Anurag-05-prog requested review from a team as code owners January 18, 2025 16:18
@semanticdiff-com
Copy link

semanticdiff-com bot commented Jan 18, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/connector_configs/src/transformer.rs  80% smaller
  crates/hyperswitch_connectors/src/connectors/square/transformers.rs  67% smaller
  crates/hyperswitch_connectors/src/connectors/noon/transformers.rs  52% smaller
  crates/hyperswitch_connectors/src/connectors/fiuu/transformers.rs  48% smaller
  crates/hyperswitch_connectors/src/connectors/bankofamerica/transformers.rs  48% smaller
  crates/hyperswitch_connectors/src/connectors/cybersource/transformers.rs  48% smaller
  crates/hyperswitch_connectors/src/connectors/wellsfargo/transformers.rs  48% smaller
  crates/hyperswitch_connectors/src/connectors/barclaycard/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/bluesnap/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/checkout/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/globepay/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/mifinity/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/multisafepay/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/nmi/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/nuvei/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/payme/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/paypal/transformers.rs  43% smaller
  crates/hyperswitch_connectors/src/connectors/aci/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/shift4/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/worldpay/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/zen/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/authorizedotnet/transformers.rs  37% smaller
  crates/hyperswitch_connectors/src/connectors/novalnet/transformers.rs  36% smaller
  crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs  34% smaller
  crates/hyperswitch_connectors/src/connectors/airwallex/transformers.rs  30% smaller
  crates/hyperswitch_connectors/src/connectors/boku/transformers.rs  30% smaller
  crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs  30% smaller
  crates/payment_methods/src/configs/payment_connector_required_fields.rs  20% smaller
  crates/hyperswitch_connectors/src/connectors/amazonpay/transformers.rs  17% smaller
  crates/hyperswitch_connectors/src/connectors/amazonpay.rs  9% smaller
  crates/api_models/src/payments.rs  3% smaller
  crates/common_utils/src/crypto.rs  3% smaller
  crates/openapi/src/openapi.rs  2% smaller
  crates/openapi/src/openapi_v2.rs  2% smaller
  Cargo.lock Unsupported file format
  api-reference/v1/openapi_spec_v1.json  0% smaller
  api-reference/v2/openapi_spec_v2.json  0% smaller
  config/config.example.toml Unsupported file format
  config/deployments/integration_test.toml Unsupported file format
  config/deployments/production.toml Unsupported file format
  config/deployments/sandbox.toml Unsupported file format
  config/development.toml Unsupported file format
  config/docker_compose.toml Unsupported file format
  crates/api_models/src/admin.rs  0% smaller
  crates/common_enums/src/connector_enums.rs  0% smaller
  crates/common_utils/Cargo.toml Unsupported file format
  crates/common_utils/src/errors.rs  0% smaller
  crates/connector_configs/src/connector.rs  0% smaller
  crates/connector_configs/toml/development.toml Unsupported file format
  crates/connector_configs/toml/production.toml Unsupported file format
  crates/connector_configs/toml/sandbox.toml Unsupported file format
  crates/hyperswitch_connectors/Cargo.toml Unsupported file format
  crates/hyperswitch_connectors/src/utils.rs  0% smaller
  crates/hyperswitch_domain_models/src/payment_method_data.rs  0% smaller
  crates/hyperswitch_domain_models/src/payments/payment_attempt.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types.rs  0% smaller
  crates/router/src/connector/utils.rs  0% smaller
  crates/router/src/core/connector_validation.rs  0% smaller
  crates/router/src/core/payments/flows/session_flow.rs  0% smaller
  crates/router/src/core/payments/helpers.rs  0% smaller
  crates/router/src/core/payments/operations/payment_session.rs  0% smaller
  crates/router/src/core/payments/operations/payment_session_intent.rs  0% smaller
  crates/router/src/core/payments/transformers.rs  0% smaller
  crates/router/src/types/api/connector_mapping.rs  0% smaller
  crates/router/src/types/api/feature_matrix.rs  0% smaller
  crates/router/src/types/connector_transformers.rs  0% smaller
  crates/router/tests/connectors/sample_auth.toml Unsupported file format
  crates/test_utils/src/connector_auth.rs  0% smaller
  loadtest/config/development.toml Unsupported file format

@Anurag-05-prog Anurag-05-prog changed the title Amazon pay flows feat(connector): [AMAZONPAY] add Payment flows for Amazon Pay Wallet Jan 18, 2025
@Anurag-05-prog Anurag-05-prog self-assigned this Jan 18, 2025
@Anurag-05-prog Anurag-05-prog force-pushed the amazon-pay-flows branch 3 times, most recently from 1507918 to ee8f7ae Compare January 18, 2025 19:42
@Anurag-05-prog Anurag-05-prog added the C-feature Category: Feature request or enhancement label Jan 19, 2025
@Anurag-05-prog Anurag-05-prog force-pushed the amazon-pay-flows branch 2 times, most recently from bdb7248 to 5a41be2 Compare January 19, 2025 07:38
@Anurag-05-prog Anurag-05-prog added the A-connector-integration Area: Connector integration label Jan 20, 2025
@Anurag-05-prog Anurag-05-prog force-pushed the amazon-pay-flows branch 4 times, most recently from b633ab2 to e712eb0 Compare January 28, 2025 07:18
@Anurag-05-prog Anurag-05-prog added the M-api-contract-changes Metadata: This PR involves API contract changes label Jan 29, 2025
Copy link
Contributor

Choose a reason for hiding this comment

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

Add these configs to hyperswitch/loadtest/config/development.toml

@hyperswitch-bot hyperswitch-bot bot removed the M-api-contract-changes Metadata: This PR involves API contract changes label Jan 31, 2025
@Anurag-05-prog Anurag-05-prog force-pushed the amazon-pay-flows branch 3 times, most recently from db43923 to b261a93 Compare February 8, 2025 05:39
Comment on lines 6734 to 6826
pub struct AmazonPaySessionTokenResponse {
pub merchant_id: String,
pub ledger_currency: String,
pub store_id: String,
pub payment_intent: String,
pub total_shipping_amount: StringMajorUnit,
pub total_tax_amount: StringMajorUnit,
pub total_base_amount: StringMajorUnit,
pub delivery_options: Vec<AmazonPayDeliveryOption>,
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPayDeliveryOption {
pub id: String,
pub price: AmazonPayDeliveryPrice,
pub shipping_method: AmazonPayShippingMethod,
pub is_default: bool,
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPayDeliveryPrice {
pub amount: String,
pub currency_code: String,
}

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPayShippingMethod {
pub shipping_method_name: String,
pub shipping_method_code: String,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Add documentation for every filed in the api_models.

#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AmazonPayMerchantCredentials {
pub merchant_id: String,
pub store_id: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

Add documentation for this field as well

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPayDeliveryPrice {
pub amount: String,
pub currency_code: 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 this be made as enum

match value {
enums::WalletType::GooglePay => Self::GooglePay,
enums::WalletType::AmazonPay => Self::AmazonPay,
enums::WalletType::GooglePay => Self::GooglePay,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change required ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reverted the change

}
global_enums::PaymentMethodType::AmazonPay => Ok(dirval!(WalletType = AmazonPay)),
global_enums::PaymentMethodType::GooglePay => Ok(dirval!(WalletType = GooglePay)),
global_enums::PaymentMethodType::AmazonPay => Ok(dirval!(WalletType = AmazonPay)),
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change required ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Needed to match every PaymentMethodType


#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPayDeliveryPrice {
pub amount: 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 amount be of type StringMajorUnit ?

#[derive(Debug, Clone, Eq, PartialEq, serde::Serialize, ToSchema)]
pub struct AmazonPaySessionTokenResponse {
pub merchant_id: String,
pub ledger_currency: 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 this be enum ?

pub merchant_id: String,
pub ledger_currency: String,
pub store_id: String,
pub payment_intent: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

As we are hardcoding payment_intent to AuthorizeWithCapture while creating session token, this can be made a enum ?

Or while creating session token we can create a const for AuthorizeWithCapture and add a comment line explaining the reason for hardcoding it.

.map(|options| {
options
.iter()
.filter_map(|option| {
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 checking for every required field here, you can create a AmazonPayDeliveryOptions struct that will have all these fields as mandatory and have a try_from for the conversation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Instead of using try_from, I created a function to parse AmazonPayDeliveryOptions. If any field is missing, the function returns an error, resulting in an empty array for the session_token in AmazonPay.


let is_default = option.get("is_default")?.as_bool()?;

Some(AmazonPayDeliveryOption {
Copy link
Contributor

Choose a reason for hiding this comment

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

Also as per this logic if any one of the required field is not present in the particular delivery option, that element will be considered as None and we will check for new element.

Example:

"metadata": {
        "delivery_options": [
            {
                "id": "standard-delivery",
                "price":{
                    "amount": "20.00",
                    "currency_code":"USD"
                },
                "shipping_method":{

                    "shipping_method_code":"standard-courier"
                },
                "is_default":true    
            },
            {
                "id":"express-delivery",
                "price":{
                    "amount":"50",
                    "currency_code":"USD"
                },
                "shipping_method":{
                    "shipping_method_name":"express-courier",
                    "shipping_method_code":"express-courier"
                },
                "is_default":false 
            }
        ]
    },

In the above shipping_method_name is missing for standard-delivery hence that delivery_options in the session response will contain only express-delivery. Is it expected ?

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 is not expected. Changed the code to show the expected behavior.

ext_traits::ByteSliceExt,
request::RequestContent,
types::{AmountConvertor, StringMajorUnitForConnector},
// transformers::ForeignTryFrom,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change required ?

// transformers::ForeignTryFrom,
types::{AmountConvertor, MinorUnit, StringMajorUnitForConnector},
};
// use std::convert::TryFrom;
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change required ?

use api_models::{
payments as payment_types,
payments::{
AmazonPayDeliveryOptions, AmazonPayDeliveryPrice, AmazonPayPaymentIntent,
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 directly importing the type, consider using payment_types::AmazonPayDeliveryOptions wherever required.

Same for other types

) -> Result<AmazonPayDeliveryOptions, errors::ApiErrorResponse> {
let id = value
.get("id")
.and_then(|v| v.as_str())
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider renaming the variable 'v' to something more descriptive, like 'id_value'

.ok_or(errors::ApiErrorResponse::MissingRequiredField { field_name: "id" })?
.to_string();

let price = value
Copy link
Contributor

Choose a reason for hiding this comment

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

I see that every time you are trying to get a value form metadata which is of type serde_json::Value. I think we can have a AmazonPayDeliveryOption struct that mandates all these fields like id, price etc and the parse metadata to that type.

deepanshu-iiitu
deepanshu-iiitu previously approved these changes Aug 6, 2025
@Anurag-05-prog Anurag-05-prog removed the request for review from JeevaRamu0104 August 28, 2025 19:39
nutype = { version = "0.4.3", features = ["serde"] }
once_cell = "1.21.3"
openssl = {version = "0.10.72", optional = true}
pem = "2.0.0"
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 this ?

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 is required for writing unit test for signature generation process in Amazon Pay requests.

@likhinbopanna likhinbopanna added this pull request to the merge queue Aug 29, 2025
Merged via the queue into main with commit 23cf437 Aug 29, 2025
21 of 25 checks passed
@likhinbopanna likhinbopanna deleted the amazon-pay-flows branch August 29, 2025 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-connector-integration Area: Connector integration C-feature Category: Feature request or enhancement M-api-contract-changes Metadata: This PR involves API contract changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants