Skip to content

feat(core): Hyperswitch <|> UCS integration v2 #8439

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 86 commits into from
Jul 11, 2025

Conversation

maverox
Copy link
Contributor

@maverox maverox commented Jun 24, 2025

Type of Change

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

Fixes #8440

Description

This PR implements V2 UCS (Unified Connector Service) Integration for authorization and synchronization flows, building upon the existing V1 UCS integration (PR#8280), with enhanced
V2 schema support according to updated gRPC contract.

Key Features Implemented:

  1. Authorization Flow (Payments): Full V2 schema support for payment authorization
  2. PSync Flow: Payment status synchronization through UCS V2
  3. UPI Payment Method: Support for UPI Collect payment method
  4. Enhanced Response Handling: Improved status mapping and error handling
  5. Address Transformation Fix: Better handling of optional address fields

Key Changes from V1 to V2:

  1. Updated gRPC Schema:

    • Migrated from PaymentsAuthorizeRequest to PaymentServiceAuthorizeRequest
    • Added PaymentServiceGetRequest for PSync flow
    • Enhanced field structure for better type safety
  2. New Payment Methods:

    • Added UPI Collect payment method support
    • Proper VPA ID extraction and handling
  3. Enhanced Transformers:

    • Updated transformers for authorization and sync flows
    • Improved card details, address structure, and payment method handling
    • Fixed address transformation to handle None values gracefully
  4. V2 Flow Architecture:

    • Refactored payment flow to separate UCS prerequisites and decision logic
    • Added PSync flow integration through UCS
    • Feature flag protection for clean V1/V2 separation
  5. Improved Response Handling:

    • Enhanced response parsing with new identifier structure
    • Added support for more payment states (Started, AuthenticationSuccessful, Authorizing, etc.)
    • Better error handling and status mapping

V2 Architecture Flow:
V2 Payment Request → call_connector_service_prerequisites() → decide_unified_connector_service_call() →
├── UCS Available → V2 Transformers → gRPC Call → V2 Response Handling
└── UCS Unavailable → Traditional Connector Flow (Fallback)

V2 PSync Request → call_unified_connector_service() →
├── UCS Available → V2 PSync Transformer → gRPC Get Call → Status Response
└── UCS Unavailable → Traditional Connector Sync Flow

Key Technical Improvements:

  • Refactored Payment Functions: Split call_connector_service() into call_connector_service_prerequisites() and decide_unified_connector_service_call() for better separation of concerns
  • Enhanced V2 Transformers: Updated card data transformation, address structure, and authentication data handling
  • PSync Flow Integration: Added complete payment synchronization support through UCS
  • UPI Payment Support: Added UPI Collect payment method with VPA ID handling
  • Improved Error Handling: Better response parsing with new identifier structure
  • Customer ID Support: Added customer ID mapping in V2 transformer implementation
  • Enhanced Authentication: Added tenant_id and merchant_id to ConnectorAuthMetadata

Files Modified:

  • crates/router/Cargo.toml - Updated rust-grpc-client dependency to main branch
  • crates/router/src/core/payments.rs - Refactored UCS integration with V2 prerequisite and decision functions
  • crates/router/src/core/payments/flows/authorize_flow.rs - Updated to use PaymentServiceAuthorizeRequest
  • crates/router/src/core/payments/flows/psync_flow.rs - Added UCS V2 support for payment synchronization
  • crates/router/src/core/payments/transformers.rs - Added V2 PaymentsAuthorizeData transformer implementation and customer_id support
  • crates/router/src/core/unified_connector_service/ - Updated transformers and response handlers for V2 schema
  • crates/router/src/core/unified_connector_service.rs - Added UPI payment method support and enhanced response handling
  • crates/router/src/core/unified_connector_service/transformers.rs - Major updates for V2 gRPC schema compatibility
  • crates/external_services/src/grpc_client/unified_connector_service.rs - Added payment get operations support

Additional Changes

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

Motivation and Context

V2 UCS Integration Evolution:

This change builds upon the existing V1 UCS integration to support the updated V2 gRPC schema and enhanced payment flow architecture. Key motivations:

Schema Evolution:

  • Updated gRPC Contracts: V2 introduces improved field structures for better type safety and extensibility
  • Enhanced Data Models: New card details structure, improved address handling, and better identifier management
  • Backward Compatibility: V2 implementation maintains compatibility while leveraging new schema features

Feature Additions:

  • PSync Flow Support: Enables payment status synchronization through UCS, reducing direct connector calls
  • UPI Payment Method: Adds support for popular Indian payment method through unified interface
  • Enhanced Status Handling: More granular payment states for better payment lifecycle tracking

Architectural Improvements:

  • Separation of Concerns: Split monolithic UCS functions into prerequisite preparation and decision logic phases
  • Better Feature Flag Management: Clean V1/V2 separation using #[cfg(feature = "v2")] prevents conflicts
  • Enhanced Error Handling: Improved response parsing and identifier handling for better reliability
  • Maintainability: Cleaner code structure for easier debugging and future enhancements

Business Value:

  • Future-Proofing: V2 schema supports upcoming UCS enhancements and new payment flows
  • Improved Reliability: Better error handling and response parsing reduces failure rates
  • Enhanced Developer Experience: Cleaner API interfaces and better type safety
  • Operational Excellence: Maintains existing rollout controls while improving monitoring capabilities
  • Broader Payment Support: UPI integration opens up access to Indian market payment preferences

How did you test it?

Manual Testing (HAPPY CASE)

V2 Payment Intent Creation (Adyen via UCS)

Request:

curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'Authorization: api-key=dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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"
        }
    },
    "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"
        }
    }
}'

Response:

{
    "id": "12345_pay_0197ac4f440c73c0b34c7050d248e483",
    "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_0197ac4f4421744094d3abffdeae634c",
    "profile_id": "pro_2MBjeGslBsr2Lr7AoLvr",
    "merchant_reference_id": null,
    "routing_algorithm_id": null,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "default",
    "expires_on": "2025-06-26T13:11:05.403Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip"
}

V2 Payment Confirmation (Adyen via UCS)

Request:

curl --location 'http://localhost:8080/v2/payments/12345_pay_0197ac4f440c73c0b34c7050d248e483/confirm-intent' \
--header 'x-client-secret: cs_0197ac4f4421744094d3abffdeae634c' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-connected-merchant-id: cloth_seller_2_X5u3WjKKaUMMtPMYCNQM' \
--header 'Authorization: publishable-key=pk_dev_b78d41b686d54407842e55c1be492fce,client-secret=cs_0197ac4f4421744094d3abffdeae634c' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_b78d41b686d54407842e55c1be492fce' \
--data '{
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "03",
            "card_exp_year": "30",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "737"
        }
    },
    "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
    }
}'

Response:

{
    "id": "12345_pay_0197ac4f440c73c0b34c7050d248e483",
    "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": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "connector": "adyen",
    "created": "2025-06-26T12:56:05.403Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "connector_transaction_id": "12345_pay_0197ac4f440c73c0b34c7050d248e483",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_YUhrsoeHfh0EQJE6Zqut",
    "browser_info": null,
    "error": 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": null
}

V2 Payment Intent Creation (Adyen via Traditional Connector Flow)

Request:

curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'Authorization: api-key=dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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"
        }
    },
    "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"
        }
    }
}'

Response:

{
    "id": "12345_pay_0197ac4c67657d81a796bc358b364d04",
    "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_0197ac4c67ac7731907d52f9dac88996",
    "profile_id": "pro_2MBjeGslBsr2Lr7AoLvr",
    "merchant_reference_id": null,
    "routing_algorithm_id": null,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "default",
    "expires_on": "2025-06-26T13:07:57.887Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip"
}

V2 Payment Confirmation (Adyen via Traditional Connector Flow)

Request:

curl --location 'http://localhost:8080/v2/payments/12345_pay_0197ac4c67657d81a796bc358b364d04/confirm-intent' \
--header 'x-client-secret: cs_0197ac4c67ac7731907d52f9dac88996' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-connected-merchant-id: cloth_seller_2_X5u3WjKKaUMMtPMYCNQM' \
--header 'Authorization: publishable-key=pk_dev_b78d41b686d54407842e55c1be492fce,client-secret=cs_0197ac4c67ac7731907d52f9dac88996' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_b78d41b686d54407842e55c1be492fce' \
--data '{
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "03",
            "card_exp_year": "30",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "737"
        }
    },
    "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
    }
}'

Response:

{
    "id": "12345_pay_0197ac4c67657d81a796bc358b364d04",
    "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": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "connector": "adyen",
    "created": "2025-06-26T12:52:57.887Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "connector_transaction_id": "K2LGMPJFQZ9TPM75",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_YUhrsoeHfh0EQJE6Zqut",
    "browser_info": null,
    "error": 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": null
}

Manual Testing (FAILURE CASE)

V2 Payment Intent Creation (Adyen via UCS)

Request:

curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'Authorization: api-key=dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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"
        }
    },
    "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"
        }
    }
}'

Response:

{
    "id": "12345_pay_0197ac52cee5796099a0ae352092a707",
    "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_0197ac52cefb77e2be6097f5d54b1152",
    "profile_id": "pro_2MBjeGslBsr2Lr7AoLvr",
    "merchant_reference_id": null,
    "routing_algorithm_id": null,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "default",
    "expires_on": "2025-06-26T13:14:57.559Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip"
}

V2 Payment Confirmation (Adyen via UCS)

Request:

curl --location 'http://localhost:8080/v2/payments/12345_pay_0197ac52cee5796099a0ae352092a707/confirm-intent' \
--header 'x-client-secret: cs_0197ac52cefb77e2be6097f5d54b1152' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-connected-merchant-id: cloth_seller_2_X5u3WjKKaUMMtPMYCNQM' \
--header 'Authorization: publishable-key=pk_dev_b78d41b686d54407842e55c1be492fce,client-secret=cs_0197ac52cefb77e2be6097f5d54b1152' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_b78d41b686d54407842e55c1be492fce' \
--data '{
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "03",
            "card_exp_year": "30",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "730"
        }
    },
    "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
    }
}'

Response:

{
    "id": "12345_pay_0197ac52cee5796099a0ae352092a707",
    "status": "failed",
    "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": 0
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "connector": "adyen",
    "created": "2025-06-26T12:59:57.559Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "connector_transaction_id": "G4QT66CH8WCFHJ75",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_YUhrsoeHfh0EQJE6Zqut",
    "browser_info": null,
    "error": {
        "code": "24",
        "message": "CVC Declined",
        "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": null
}

V2 Payment Intent Creation (Adyen via Traditional Connector Flow)

Request:

curl --location 'http://localhost:8080/v2/payments/create-intent' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--header 'Content-Type: application/json' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'Authorization: api-key=dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data '{
    "amount_details": {
        "order_amount": 100,
        "currency": "USD"
    },
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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"
        }
    },
    "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"
        }
    }
}'

Response:

{
    "id": "12345_pay_0197ac5574b37982b150606298590cfb",
    "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_0197ac5574c57c50b773a7230ffffe69",
    "profile_id": "pro_2MBjeGslBsr2Lr7AoLvr",
    "merchant_reference_id": null,
    "routing_algorithm_id": null,
    "capture_method": "automatic",
    "authentication_type": "no_three_ds",
    "billing": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "shipping": {
        "address": {
            "city": "San Fransico",
            "country": "US",
            "line1": "1467",
            "line2": "Harrison Street",
            "line3": "Harrison Street",
            "zip": "94122",
            "state": "California",
            "first_name": "joseph",
            "last_name": "Doe"
        },
        "phone": null,
        "email": null
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "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": null,
    "connector_metadata": null,
    "feature_metadata": null,
    "payment_link_enabled": "Skip",
    "payment_link_config": null,
    "request_incremental_authorization": "default",
    "expires_on": "2025-06-26T13:17:51.072Z",
    "frm_metadata": null,
    "request_external_three_ds_authentication": "Skip"
}

V2 Payment Confirmation (Adyen via Traditional Connector Flow)

Request:

curl --location 'http://localhost:8080/v2/payments/12345_pay_0197ac5574b37982b150606298590cfb/confirm-intent' \
--header 'x-client-secret: cs_0197ac5574c57c50b773a7230ffffe69' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-connected-merchant-id: cloth_seller_2_X5u3WjKKaUMMtPMYCNQM' \
--header 'Authorization: publishable-key=pk_dev_b78d41b686d54407842e55c1be492fce,client-secret=cs_0197ac5574c57c50b773a7230ffffe69' \
--header 'Content-Type: application/json' \
--header 'api-key: pk_dev_b78d41b686d54407842e55c1be492fce' \
--data '{
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "payment_method_data": {
        "card": {
            "card_number": "4111111111111111",
            "card_exp_month": "03",
            "card_exp_year": "30",
            "card_holder_name": "Joseph Doe",
            "card_cvc": "730"
        }
    },
    "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
    }
}'

Response:

{
    "id": "12345_pay_0197ac5574b37982b150606298590cfb",
    "status": "failed",
    "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": 0
    },
    "customer_id": "12345_cus_0197abe38df57a408b928b4111ff5038",
    "connector": "adyen",
    "created": "2025-06-26T13:02:51.072Z",
    "payment_method_data": {
        "billing": null
    },
    "payment_method_type": "card",
    "payment_method_subtype": "credit",
    "connector_transaction_id": "DXZQPDL34QGTPM75",
    "connector_reference_id": null,
    "merchant_connector_id": "mca_YUhrsoeHfh0EQJE6Zqut",
    "browser_info": null,
    "error": {
        "code": "24",
        "message": "CVC Declined",
        "unified_code": null,
        "unified_message": null,
        "network_advice_code": null,
        "network_decline_code": null,
        "network_error_message": "DECLINED CVC Incorrect"
    },
    "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": null
}

###UPI Collect payment through UCS
Request

curl --location 'http://localhost:8080/v2/payments' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-merchant-id: cloth_seller_2_H3Oh1h4iu0wg8BWGvMzu' \
--header 'x-tenant-id: public' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data-raw '{
    "amount_details": {
        "currency": "INR",
        "order_amount": 1000
    },    
    "merchant_connector_details": {
        "connector_name": "razorpay",
        "merchant_connector_creds": {
            "auth_type": "SignatureKey",
            "key1": "*************************",
            "api_key": "********************",
            "api_secret": "*******************"
        }
    },
    "merchant_reference_id": "12345_pay_01970c787911751013554",
    "payment_method_data": {
        "upi": {
            "upi_collect": {
                "vpa_id": "failure@razorpay"
            }
        },
        "billing": {
            "phone": {
                "number": "8800574493",
                "country_code": "+91"
            },
            "email": "[email protected]"
        }
    },
    "payment_method_subtype": "upi_collect",
    "payment_method_type": "upi"
}'

Response

{
    "id": "12345_pay_0197ceee564473609731b2ab35827cc7",
    "status": "processing",
    "amount": {
        "order_amount": 1000,
        "currency": "INR",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null,
        "net_amount": 1000,
        "amount_to_capture": null,
        "amount_capturable": 0,
        "amount_captured": null
    },
    "customer_id": null,
    "connector": "razorpay",
    "created": "2025-07-03T06:16:55.621Z",
    "payment_method_data": {
        "billing": {
            "address": null,
            "phone": {
                "number": "8800574493",
                "country_code": "+91"
            },
            "email": "[email protected]"
        }
    },
    "payment_method_type": "upi",
    "payment_method_subtype": "upi_collect",
    "connector_transaction_id": "pay_QoUbCBtcPCfaWY",
    "connector_reference_id": "order_QoUbBDL6PKnuZY",
    "merchant_connector_id": null,
    "browser_info": null,
    "error": 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": null,
    "authentication_type_applied": "no_three_ds",
    "is_iframe_redirection_enabled": null,
    "merchant_reference_id": "12345_pay_01970c787911751013554",
    "whole_connector_response": null
}

PSync through UCS

Request

curl --location 'http://localhost:8080/v2/payments/12345_pay_0197ceee564473609731b2ab35827cc7' \
--header 'x-profile-id: pro_2MBjeGslBsr2Lr7AoLvr' \
--header 'x-merchant-id: cloth_seller_2_H3Oh1h4iu0wg8BWGvMzu' \
--header 'x-tenant-id: public' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_ymXSN8By3WESknjGnFyLVwDE4tK9v8ZjnkMZsKb2cM7KgjlzLfU1SOnJ63LsIrfR' \
--data '{
    "merchant_connector_details": {
        "connector_name": "razorpay",
        "merchant_connector_creds": {
            "auth_type": "SignatureKey",
            "key1": "**************",
            "api_key": "********************",
            "api_secret": "******************"
        }
    },
    "force_sync": true
}'```
*Response*
```json
{
    "id": "12345_pay_0197ceee564473609731b2ab35827cc7",
    "status": "failed",
    "amount": {
        "order_amount": 1000,
        "currency": "INR",
        "shipping_cost": null,
        "order_tax_amount": null,
        "external_tax_calculation": "skip",
        "surcharge_calculation": "skip",
        "surcharge_amount": null,
        "tax_on_surcharge": null,
        "net_amount": 1000,
        "amount_to_capture": null,
        "amount_capturable": 0,
        "amount_captured": 0
    },
    "customer_id": null,
    "connector": "razorpay",
    "created": "2025-07-03T06:16:55.621Z",
    "payment_method_data": {
        "billing": {
            "address": null,
            "phone": {
                "number": "8800574493",
                "country_code": "+91"
            },
            "email": "[email protected]"
        }
    },
    "payment_method_type": "upi",
    "payment_method_subtype": "upi_collect",
    "connector_transaction_id": "pay_QoUbCBtcPCfaWY",
    "connector_reference_id": "order_QoUbBDL6PKnuZY",
    "merchant_connector_id": null,
    "browser_info": null,
    "error": {
        "code": "",
        "message": "",
        "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": null,
    "authentication_type_applied": null,
    "is_iframe_redirection_enabled": null,
    "merchant_reference_id": "12345_pay_01970c787911751013554",
    "whole_connector_response": null
}

V2 Schema Testing:

  • V2 gRPC schema compatibility verification
  • PaymentServiceAuthorizeRequest field mapping validation
  • Enhanced card details and address structure testing
  • Response identifier parsing with new structure

Fallback Testing:

  • UCS service unavailable → Automatic fallback to traditional connector flow
  • Invalid authentication → Fallback with error logging
  • V2 transformer errors → Graceful degradation to V1 flow
  • Rollout percentage = 0% → Traditional flow used
  • Rollout percentage = 100% → UCS V2 flow used

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

@maverox maverox requested review from a team as code owners June 24, 2025 06:16
Copy link

semanticdiff-com bot commented Jun 24, 2025

@maverox maverox changed the title Hyperswitch ucs integration v2 feat(core): Hyperswitch <|> UCS integration v2 Jun 24, 2025
@maverox maverox self-assigned this Jun 24, 2025
@maverox maverox changed the base branch from main to hyperswitch_ucs_integration June 24, 2025 06:20
@maverox maverox requested a review from a team as a code owner June 26, 2025 08:31
@maverox maverox changed the base branch from hyperswitch_ucs_integration to main June 27, 2025 06:36
@maverox maverox requested review from jarnura and SanchithHegde June 27, 2025 06:37
@maverox maverox changed the base branch from main to hyperswitch_ucs_integration June 27, 2025 08:46
@Aishwariyaa-Anand Aishwariyaa-Anand requested a review from a team as a code owner June 27, 2025 09:51
@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Jun 27, 2025
@maverox maverox changed the base branch from hyperswitch_ucs_integration to main July 1, 2025 08:19
@Aishwariyaa-Anand Aishwariyaa-Anand requested a review from a team as a code owner July 1, 2025 12:16
@maverox maverox changed the base branch from main to hyperswitch_ucs_integration July 2, 2025 07:21
@maverox maverox requested review from a team as code owners July 2, 2025 07:21
@maverox maverox changed the base branch from hyperswitch_ucs_integration to main July 2, 2025 07:22
@maverox maverox added A-core Area: Core flows C-feature Category: Feature request or enhancement and removed M-api-contract-changes Metadata: This PR involves API contract changes labels Jul 3, 2025
@hyperswitch-bot hyperswitch-bot bot added the M-api-contract-changes Metadata: This PR involves API contract changes label Jul 3, 2025
@maverox maverox changed the base branch from main to hyperswitch_ucs_integration July 3, 2025 07:39
@maverox maverox changed the base branch from hyperswitch_ucs_integration to main July 3, 2025 08:33
Comment on lines 102 to 109
/// Optional API key used for authentication.
pub api_key: Option<String>,

/// Optional additional key used by some authentication types.
pub key1: Option<String>,

/// Optional API secret used for signature or secure authentication.
pub api_secret: Option<String>,
Copy link
Member

Choose a reason for hiding this comment

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

These fields would have to be Secret.

@@ -200,7 +200,7 @@ outgoing_enabled = true
redis_lock_expiry_seconds = 180 # 3 * 60 seconds

[merchant_id_auth]
merchant_id_auth_enabled = false
merchant_id_auth_enabled = true
Copy link
Member

Choose a reason for hiding this comment

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

Can we revert this change?

Comment on lines 38 to 39
/// Header key used to specify the connector name in UCS requests.
pub const UCS_HEADER_CONNECTOR: &str = "x-connector";
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Can we make the constants only used in this crate to be pub(crate)?

Comment on lines 222 to 234
#[cfg(feature = "frm")]
None,
#[cfg(not(feature = "frm"))]
None,
Copy link
Member

Choose a reason for hiding this comment

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

Nit: We can just pass None always, without the feature gates.

Suggested change
#[cfg(feature = "frm")]
None,
#[cfg(not(feature = "frm"))]
None,
None,

Comment on lines 296 to 314
#[cfg(feature = "frm")]
None,
#[cfg(not(feature = "frm"))]
None,
Copy link
Member

Choose a reason for hiding this comment

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

Same here.

@maverox maverox requested review from a team and removed request for a team July 8, 2025 08:56
jarnura
jarnura previously approved these changes Jul 8, 2025
@SanchithHegde SanchithHegde removed request for a team July 8, 2025 19:36
Comment on lines 127 to 133
_ => {
return Err(UnifiedConnectorServiceError::NotImplemented(format!(
"Unimplemented card payment method type: {:?}",
payment_method_type
))
.into());
}
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Why does the error message say "card payment method type"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I will change it to "Unimplemented card type: {:?}"

Copy link
Member

Choose a reason for hiding this comment

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

But this is not a card payment method at all right, we were matching against UPI data?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah bro based on payment_method_type we are creating the pm data
So it has both cards and upi for now and will extend further

SanchithHegde
SanchithHegde previously approved these changes Jul 9, 2025
Comment on lines 4126 to +4127
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
Copy link
Member

Choose a reason for hiding this comment

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

Nit: You can combine these two lines.

Suggested change
#[allow(clippy::too_many_arguments)]
#[allow(clippy::type_complexity)]
#[allow(clippy::too_many_arguments, clippy::type_complexity)]

@likhinbopanna likhinbopanna added this pull request to the merge queue Jul 11, 2025
Merged via the queue into main with commit ae9feca Jul 11, 2025
14 of 20 checks passed
@likhinbopanna likhinbopanna deleted the hyperswitch_ucs_integration_v2 branch July 11, 2025 14:44
pixincreate added a commit that referenced this pull request Jul 11, 2025
…ayload-webhooks

* 'main' of github.com:juspay/hyperswitch:
  feat(payments): propagate additional payment method data for apple pay during MIT (#7170)
  feat(core): Hyperswitch <|> UCS integration v2 (#8439)
  feat(connector): [payload] add webhook support (#8558)
  ci(cypress): Added Dlocal Connector Test (#8362)
  feat(connector): [AIRWALLEX] - Added Paypal, Trustly, Klarna , Atome, Blik Payment Methods (#8475)
  refactor(cypress): update skip logic and test flow for cypress incremental auth tests (#8594)
  chore(version): 2025.07.11.0
  chore: address Rust 1.88.0 clippy lints (#8607)
  chore(version): 2025.07.10.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-core Area: Core flows C-feature Category: Feature request or enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[FEATURE] Implement V2 UCS (Unified Connector Service) Integration for Authorization Flow
6 participants