Skip to content

feat(router): add support for overcapture#8949

Merged
likhinbopanna merged 55 commits intomainfrom
overcapture-extended
Sep 9, 2025
Merged

feat(router): add support for overcapture#8949
likhinbopanna merged 55 commits intomainfrom
overcapture-extended

Conversation

@AkshayaFoiger
Copy link
Contributor

@AkshayaFoiger AkshayaFoiger commented Aug 14, 2025

Type of Change

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

Description

Overcapture allows a merchant to capture more than the originally authorized amount for a transaction. In most cases, this is controlled by a connector-level configuration. However, some connectors (such as Stripe) also allow merchants to explicitly request overcapture via the Payments API.

Proposed Solution:

  1. When confirm = false and capture is manual
    payment_intent.enable_overcapture = request.enable_overcapture

  2. When confirm = true and capture is manual

    • If request.enable_overcapture is present →
      payment_intent.enable_overcapture = request.enable_overcapture
    • If not present →
      payment_intent.enable_overcapture = profile.always_enable_overcapture
  3. Some connectors return a flag (e.g., is_overcapture_enabled) in the authorization response along with the maximum capturable amount. We store this in the payment attempt and expose it in the payments response.

  4. If the connector does not return either the flag or the capturable amount, we fall back to mapping payment_intent.enable_overcapture to the is_overcapture_enabled flag in the payment attempt. This ensures overcapture is treated as supported whenever the merchant has enabled it at the connector level.

Overcapture is integrated for Stripe and Adyen

Additional Changes

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

How did you test it?

Configure Always-On Overcapture and Execute Stripe Payment

Update profile to always enable overcapture

curl --location 'http://localhost:8080/account/postman_merchant_GHAction_6ce5b010-70e5-4dd0-a6bc-3ac01eaa3cd2/business_profile/pro_rn8ZFoa2KfpUzAKNoSno' \
--header 'Content-Type: application/json' \
--header 'api-key: dev_py7dOTdNEVlLr9VIZQyCHseeqbfi1VTWcREDapd6DzPiLrjIjuvHI47rOpiFRMGY' \
--data '{


"always_enable_overcapture": true

}'

Response

{"merchant_id":"postman_merchant_GHAction_6ce5b010-70e5-4dd0-a6bc-3ac01eaa3cd2","profile_id":"pro_rn8ZFoa2KfpUzAKNoSno","profile_name":"US_default","return_url":"https://duck.com/success","enable_payment_response_hash":true,"payment_response_hash_key":"lZdGfbaacey4V87OxDmJwE4yyCEx2TahL0tUcEN3ycgbIev3EU0enx6kgBYGq9CB","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":null,"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,"routing_algorithm":null,"intent_fulfillment_time":900,"frm_routing_algorithm":null,"payout_routing_algorithm":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":false,"collect_billing_details_from_wallet_connector":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,"tax_connector_id":null,"is_tax_connector_enabled":false,"is_network_tokenization_enabled":false,"is_auto_retries_enabled":false,"max_auto_retries_enabled":null,"always_request_extended_authorization":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,"force_3ds_challenge":false,"is_debit_routing_enabled":false,"merchant_business_country":null,"is_pre_network_tokenization_enabled":false,"acquirer_configs":null,"is_iframe_redirection_enabled":null,"merchant_category_code":null,"merchant_country_code":null,"dispute_polling_interval":null,"always_enable_overcapture":true}

Do a payment via stripe

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_py7dOTdNEVlLr9VIZQyCHseeqbfi1VTWcREDapd6DzPiLrjIjuvHI47rOpiFRMGY' \
--data '{
    "amount":90,
    "currency": "USD",
    "confirm": true,
    "capture_method": "manual",
    "customer_id": "aaaa",
    "payment_method": "card",
    "payment_method_type": "credit",
   
      "payment_method_data": {
        "card": {
            "card_number": "371449635398431", 
            "card_exp_month": "03",
            "card_exp_year": "30",
            
            "card_cvc": "7373"
            
        }
    },
  
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "13.232.74.226"
    }
}'

Response (The feature has to be enabled at stripe)

{"payment_id":"pay_wfYKfjNxA2mn1TbjSWSO","merchant_id":"postman_merchant_GHAction_6ce5b010-70e5-4dd0-a6bc-3ac01eaa3cd2","status":"failed","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":null,"connector":"stripe","client_secret":"pay_wfYKfjNxA2mn1TbjSWSO_secret_QbqxoHGZjAIZXuYI6JH6","created":"2025-08-21T10:38:07.323Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":"payment_intent_invalid_parameter","error_message":"This account is not eligible for the requested card features. See https://stripe.com/docs/payments/flexible-payments for more details.","unified_code":"UE_9000","unified_message":"Something went wrong","payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"aaaa","created_at":1755772687,"expires":1755776287,"secret":"epk_105fb4bbbf34472bae0ce371b1fb9253"},"manual_retry_allowed":true,"connector_transaction_id":"pi_3RyVsiAGHc77EJXX0uo45xUt","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":null,"payment_link":null,"profile_id":"pro_rn8ZFoa2KfpUzAKNoSno","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_35aOuEPFEq2yIkyUwLd5","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T10:53:07.323Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T10:38:09.129Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"enable_overcapture":true,"is_overcapture_enabled":null}

Override the profile config by passing enable_overcapture = false in the payments request

curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_py7dOTdNEVlLr9VIZQyCHseeqbfi1VTWcREDapd6DzPiLrjIjuvHI47rOpiFRMGY' \
--data '{
    "amount":90,
    "currency": "USD",
    "confirm": true,
    "capture_method": "manual",
    "enable_overcapture": false,
    "customer_id": "aaaa",
    "payment_method": "card",
    "payment_method_type": "credit",
      "payment_method_data": {
        "card": {
            "card_number": "371449635398431", 
            "card_exp_month": "03",
            "card_exp_year": "30",
            
            "card_cvc": "7373"
            
        }
    },
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "13.232.74.226"
    }
}'

Response

{"payment_id":"pay_zWQJsuoG4qI2MT8gb8k9","merchant_id":"postman_merchant_GHAction_6ce5b010-70e5-4dd0-a6bc-3ac01eaa3cd2","status":"requires_capture","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":null,"connector":"stripe","client_secret":"pay_zWQJsuoG4qI2MT8gb8k9_secret_uRgFe5562QNcNnMfCOlU","created":"2025-08-21T10:55:02.663Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":{"cvc_check":"pass","address_line1_check":null,"address_postal_code_check":null},"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"aaaa","created_at":1755773702,"expires":1755777302,"secret":"epk_b8ef720edd5a47a4b35b0edec5300d9c"},"manual_retry_allowed":false,"connector_transaction_id":"pi_3RyW95AGHc77EJXX36ci5XYK","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":"pi_3RyW95AGHc77EJXX36ci5XYK","payment_link":null,"profile_id":"pro_rn8ZFoa2KfpUzAKNoSno","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_35aOuEPFEq2yIkyUwLd5","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T11:10:02.663Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T10:55:03.751Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"enable_overcapture":false,"is_overcapture_enabled":false}

Try capturing amount greater than auth amount. This must throw an error

curl --location 'http://localhost:8080/payments/pay_zWQJsuoG4qI2MT8gb8k9/capture' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_py7dOTdNEVlLr9VIZQyCHseeqbfi1VTWcREDapd6DzPiLrjIjuvHI47rOpiFRMGY' \
--data '{
    "amount_to_capture": 100
    
    
}'

Response

{"error":{"type":"invalid_request","message":"amount_to_capture is greater than amount","code":"IR_06"}}
Verify Overcapture Support in Adyen Payments
  1. Create a manual payment with Adyen of authorization amount 90
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_89TTZdDLDA3Puic3xo10YGMmufBXe94BuS0sXqYjIV0hnNt9SfAiczVFXaueVaCZ' \
--data '{
    "amount":90,
    "currency": "USD",
    "confirm": true,
    "capture_method": "manual",
    "enable_overcapture": true,
    "customer_id": "aaaa",
    "payment_method": "card",
    "payment_method_type": "credit",
      "payment_method_data": {
        "card": {
            "card_number": "371449635398431", 
            "card_exp_month": "03",
            "card_exp_year": "30",
            
            "card_cvc": "7373"
            
        }
    },    
    "browser_info": {
        "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
        "accept_header": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
        "language": "nl-NL",
        "color_depth": 24,
        "screen_height": 723,
        "screen_width": 1536,
        "time_zone": 0,
        "java_enabled": true,
        "java_script_enabled": true,
        "ip_address": "13.232.74.226"
    }
}'

Response

{"payment_id":"pay_hukB7wTi9fIFrYMx9MJe","merchant_id":"postman_merchant_GHAction_c47479b4-7f24-48d5-84bd-04323099e49c","status":"requires_customer_action","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":null,"connector":"adyen","client_secret":"pay_hukB7wTi9fIFrYMx9MJe_secret_y1tbonfUSgq6VZhKf3P5","created":"2025-08-21T11:10:27.902Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":{"type":"redirect_to_url","redirect_to_url":"http://localhost:8080/payments/redirect/pay_hukB7wTi9fIFrYMx9MJe/postman_merchant_GHAction_c47479b4-7f24-48d5-84bd-04323099e49c/pay_hukB7wTi9fIFrYMx9MJe_1"},"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":"credit","connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"aaaa","created_at":1755774627,"expires":1755778227,"secret":"epk_fb1990165d05435eae00e6aba5f28820"},"manual_retry_allowed":null,"connector_transaction_id":"RBJS3TMVFQV4S675","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":"RBJS3TMVFQV4S675","payment_link":null,"profile_id":"pro_MBqvF5FEe1NDrV049zob","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_zEWkkYzFqtgUUSBsKgGT","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T11:25:27.901Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T11:10:28.324Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"enable_overcapture":true,"is_overcapture_enabled":true}

Complete the 3ds flow

Psync

{"payment_id":"pay_hukB7wTi9fIFrYMx9MJe","merchant_id":"postman_merchant_GHAction_c47479b4-7f24-48d5-84bd-04323099e49c","status":"requires_capture","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":null,"connector":"adyen","client_secret":"pay_hukB7wTi9fIFrYMx9MJe_secret_y1tbonfUSgq6VZhKf3P5","created":"2025-08-21T11:10:27.902Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":null,"payment_method_type":"credit","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":"RBJS3TMVFQV4S675","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":"pay_hukB7wTi9fIFrYMx9MJe_1","payment_link":null,"profile_id":"pro_MBqvF5FEe1NDrV049zob","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_zEWkkYzFqtgUUSBsKgGT","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T11:25:27.901Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T11:11:31.543Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"enable_overcapture":true,"is_overcapture_enabled":true}

Do a capture for 100 dollars

curl --location 'http://localhost:8080/payments/pay_hukB7wTi9fIFrYMx9MJe/capture' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_89TTZdDLDA3Puic3xo10YGMmufBXe94BuS0sXqYjIV0hnNt9SfAiczVFXaueVaCZ' \
--data '{
    "amount_to_capture": 100

}'

Response

{"payment_id":"pay_hukB7wTi9fIFrYMx9MJe","merchant_id":"postman_merchant_GHAction_c47479b4-7f24-48d5-84bd-04323099e49c","status":"processing","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":0,"connector":"adyen","client_secret":"pay_hukB7wTi9fIFrYMx9MJe_secret_y1tbonfUSgq6VZhKf3P5","created":"2025-08-21T11:10:27.902Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":null,"payment_method_type":"credit","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":"RBJS3TMVFQV4S675","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":"pay_hukB7wTi9fIFrYMx9MJe_1","payment_link":null,"profile_id":"pro_MBqvF5FEe1NDrV049zob","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_zEWkkYzFqtgUUSBsKgGT","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T11:25:27.901Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T11:12:03.352Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"enable_overcapture":true,"is_overcapture_enabled":true}

Setup the webhooks and you must receive a capture webhook with amount - 100 dollars after this do a Psync

{"payment_id":"pay_QFEVpcrIswPKgbhCeaun","merchant_id":"postman_merchant_GHAction_3c5d9f94-26fb-404e-bcaf-94294c12dcb8","status":"succeeded","amount":90,"net_amount":90,"shipping_cost":null,"amount_capturable":90,"amount_received":100,"connector":"adyen","client_secret":"pay_QFEVpcrIswPKgbhCeaun_secret_apGfzZZF3Iarb01284Nw","created":"2025-08-21T09:02:27.251Z","currency":"USD","customer_id":"aaaa","customer":{"id":"aaaa","name":null,"email":null,"phone":null,"phone_country_code":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":"manual","payment_method":"card","payment_method_data":{"card":{"last4":"8431","card_type":null,"card_network":null,"card_issuer":null,"card_issuing_country":null,"card_isin":"371449","card_extended_bin":null,"card_exp_month":"03","card_exp_year":"30","card_holder_name":null,"payment_checks":null,"authentication_data":null},"billing":null},"payment_token":null,"shipping":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":null,"payment_method_type":"credit","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":"NWQZPH6S6RW6DXV5","frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":{"redirect_response":null,"search_tags":null,"apple_pay_recurring_details":null,"gateway_system":"direct"},"reference_id":"pay_QFEVpcrIswPKgbhCeaun_1","payment_link":null,"profile_id":"pro_njovZk0qLxU6P9O5gqbN","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":"mca_H6LnXN9zPMDnZQNLJEMf","incremental_authorization_allowed":false,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-21T09:17:27.251Z","fingerprint":null,"browser_info":{"language":"nl-NL","time_zone":0,"ip_address":"13.232.74.226","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","color_depth":24,"java_enabled":true,"screen_width":1536,"accept_header":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8","screen_height":723,"java_script_enabled":true},"payment_channel":null,"payment_method_id":null,"network_transaction_id":null,"payment_method_status":null,"updated":"2025-08-21T09:13:21.869Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":"manual","force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null,"enable_partial_authorization":null,"request_overcapture":true,"overcapture_applied":true}

Screenshot 2025-08-25 at 2 43 14 PM

Adyen Cypress test

Screenshot 2025-08-25 at 3 23 26 PM

Checklist

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

Summary by CodeRabbit

  • New Features
    • Introduced optional overcapture on payments; responses now indicate if overcapture is enabled.
    • Added Business Profile setting to default overcapture for all payments.
    • Enabled overcapture support for Stripe and Adyen; surfaces capturable/captured minor amounts when available.
  • Validation
    • Overcapture disallowed with automatic capture; improved status handling for partial and over-capture scenarios.
  • API
    • OpenAPI updated with new request/response fields for overcapture.
  • Infrastructure
    • Added database columns to track overcapture on payment intents, attempts, and business profiles.

@AkshayaFoiger AkshayaFoiger requested review from a team as code owners August 14, 2025 06:02
@semanticdiff-com
Copy link

semanticdiff-com bot commented Aug 14, 2025

Review changes with  SemanticDiff

Changed Files
File Status
  crates/router/src/core/payments/operations/payment_capture.rs  66% smaller
  crates/router/src/connector/utils.rs  36% smaller
  crates/hyperswitch_connectors/src/connectors/adyen/transformers.rs  28% smaller
  crates/hyperswitch_connectors/src/connectors/stripe/transformers.rs  27% smaller
  cypress-tests-v2/cypress/e2e/configs/Payment/Commons.js  5% smaller
  crates/hyperswitch_domain_models/src/payments/payment_attempt.rs  1% smaller
  crates/router/src/core/payments/helpers.rs  1% smaller
  crates/hyperswitch_domain_models/src/payments.rs  1% smaller
  crates/diesel_models/src/payment_attempt.rs  1% smaller
  api-reference/v1/openapi_spec_v1.json  0% smaller
  crates/api_models/src/admin.rs  0% smaller
  crates/api_models/src/payments.rs  0% smaller
  crates/common_enums/src/connector_enums.rs  0% smaller
  crates/common_types/src/primitive_wrappers.rs  0% smaller
  crates/diesel_models/src/business_profile.rs  0% smaller
  crates/diesel_models/src/payment_intent.rs  0% smaller
  crates/diesel_models/src/schema.rs  0% smaller
  crates/diesel_models/src/schema_v2.rs  0% smaller
  crates/hyperswitch_connectors/src/utils.rs  0% smaller
  crates/hyperswitch_domain_models/src/business_profile.rs  0% smaller
  crates/hyperswitch_domain_models/src/payments/payment_intent.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_data.rs  0% smaller
  crates/hyperswitch_domain_models/src/router_request_types.rs  0% smaller
  crates/router/src/core/admin.rs  0% smaller
  crates/router/src/core/payments/operations/payment_confirm.rs  0% smaller
  crates/router/src/core/payments/operations/payment_create.rs  0% smaller
  crates/router/src/core/payments/operations/payment_response.rs  0% smaller
  crates/router/src/core/payments/operations/payment_update.rs  0% smaller
  crates/router/src/core/payments/retry.rs  0% smaller
  crates/router/src/core/payments/transformers.rs  0% smaller
  crates/router/src/db/events.rs  0% smaller
  crates/router/src/types.rs  0% smaller
  crates/router/src/types/api/admin.rs  0% smaller
  crates/router/src/types/api/verify_connector.rs  0% smaller
  crates/router/src/utils/user/sample_data.rs  0% smaller
  crates/router/tests/connectors/utils.rs  0% smaller
  crates/router/tests/payments.rs  0% smaller
  crates/router/tests/payments2.rs  0% smaller
  crates/storage_impl/src/mock_db/payment_attempt.rs  0% smaller
  crates/storage_impl/src/payments/payment_attempt.rs  0% smaller
  cypress-tests/cypress/e2e/configs/Payment/Adyen.js  0% smaller
  cypress-tests/cypress/e2e/configs/Payment/Utils.js  0% smaller
  cypress-tests/cypress/e2e/spec/Payment/00031-Overcapture.cy.js  0% smaller
  migrations/2025-09-08-832974_overcapture_flags_to_payment_intent_attempt_and_profile/down.sql Unsupported file format
  migrations/2025-09-08-832974_overcapture_flags_to_payment_intent_attempt_and_profile/up.sql Unsupported file format

@AkshayaFoiger AkshayaFoiger self-assigned this Aug 14, 2025
@hyperswitch-bot hyperswitch-bot bot added the M-database-changes Metadata: This PR involves database schema changes label Aug 14, 2025
@AkshayaFoiger AkshayaFoiger added A-connector-integration Area: Connector integration C-feature Category: Feature request or enhancement labels Aug 18, 2025
@AkshayaFoiger AkshayaFoiger requested a review from a team as a code owner August 25, 2025 09:17
Copy link
Contributor

@deepanshu-iiitu deepanshu-iiitu left a comment

Choose a reason for hiding this comment

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

Connector changes look good

Co-authored-by: Hrithikesh <61539176+hrithikesh026@users.noreply.github.com>
hrithikesh026
hrithikesh026 previously approved these changes Sep 4, 2025
Copy link
Contributor

@hrithikesh026 hrithikesh026 left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@ThisIsMani ThisIsMani left a comment

Choose a reason for hiding this comment

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

Dashboard specific changes looks fine.

@likhinbopanna likhinbopanna added this pull request to the merge queue Sep 9, 2025
Merged via the queue into main with commit 04a8cc4 Sep 9, 2025
21 of 25 checks passed
@likhinbopanna likhinbopanna deleted the overcapture-extended branch September 9, 2025 09:37
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 M-database-changes Metadata: This PR involves database schema changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants