feat(router): add support for partial authorization#8833
Conversation
| /// The payment has been captured partially and the remaining amount is capturable | ||
| PartiallyCapturedAndCapturable, | ||
| /// The payment has been authorized for a partial amount and requires capture | ||
| PartiallyAuthorizedAndRequiresCapture, |
There was a problem hiding this comment.
Is this status needed? Wouldn't amount_capturable indicate if the payment was Fully authorized or Partially authorized?
There was a problem hiding this comment.
There should be some explicit way of communicating the partial authorization to merchant, it's very similar to how we have PartialCharged (even though we give amount_captured value in the response)
| pub is_iframe_redirection_enabled: Option<bool>, | ||
| pub is_payment_id_from_merchant: Option<bool>, | ||
| pub payment_channel: Option<common_enums::PaymentChannel>, | ||
| pub enable_partial_authorization: Option<bool>, |
There was a problem hiding this comment.
We can make this a wrapper domain type. Like RequestIncrementalAuthorization
There was a problem hiding this comment.
In V1, we are following this convention. Can take this up in a separate PR if required
There was a problem hiding this comment.
lets takes this in a separate PR, and moving forward don't repeat this irrespective of any versions
| pub connector_meta_data: Option<common_utils::pii::SecretSerdeValue>, | ||
| pub connector_wallets_details: Option<common_utils::pii::SecretSerdeValue>, | ||
| pub amount_captured: Option<i64>, | ||
| pub amount_capturable: Option<i64>, |
There was a problem hiding this comment.
Why is this needed if minor_amount_capturable is already there
There was a problem hiding this comment.
I've added it in similar way to minor_amount_captured, currently minor_amount_captured is also not being utilized in the core. So, we are using amount_captured and amount_capturable only in payments_response_update_tracker. Introducing minor_amount_capturable allows the extensibility to possible refactor
There was a problem hiding this comment.
Amount should always be represented with MinorAmount type instead of i64
…tch into add-partial-auth-support
| pub is_iframe_redirection_enabled: Option<bool>, | ||
| pub is_payment_id_from_merchant: Option<bool>, | ||
| pub payment_channel: Option<common_enums::PaymentChannel>, | ||
| pub enable_partial_authorization: Option<bool>, |
There was a problem hiding this comment.
lets takes this in a separate PR, and moving forward don't repeat this irrespective of any versions
| pub connector_meta_data: Option<common_utils::pii::SecretSerdeValue>, | ||
| pub connector_wallets_details: Option<common_utils::pii::SecretSerdeValue>, | ||
| pub amount_captured: Option<i64>, | ||
| pub amount_capturable: Option<i64>, |
There was a problem hiding this comment.
Amount should be strictly MinorAmount only and not i64
| == capturable_amount.map(MinorUnit::new) | ||
| { | ||
| enums::AttemptStatus::Authorized | ||
| } else if capturable_amount.is_some() { |
There was a problem hiding this comment.
Here we are implicitly assuming if the object present that means PartiallyAuthorized, instead if this also the explicit key which states this is partial_auth is enabled and the amount is less then PartiallyAuthorized, in other cases if amount is less and the object present is bug, so lets avoid implicit decision making instead do deterministic explicit conditions.
| error_code: m_error_code, | ||
| error_message: m_error_message, | ||
| amount_capturable: Some(authorized_amount), | ||
| amount_capturable: if payment_data |
There was a problem hiding this comment.
Instead of having None here, have a three branch enum which has strictly no value, then non changeable authorized_amount and changeable authorized_amount
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub original_network_transaction_id: Option<Secret<String>>, | ||
| #[serde(skip_serializing_if = "Option::is_none")] | ||
| pub allow_partial_auth: Option<bool>, |
There was a problem hiding this comment.
there's a feature called partial auth that already exists which is completely different than this. Make sure no one confuses this.
…ordea-sepa * 'main' of github.com:juspay/hyperswitch: fix(router): [worldpayvantiv] dispute validations and statuses (#8862) chore(version): 2025.08.07.0 feat(connector): [WORLDPAYVANTIV] Populate Network Decline Error Code & Message (#8856) feat(router): add support for partial authorization (#8833) feat(gRPC): build gRPC client interface to initiate communication with recovery-decider service (#8178) fix(connector): [CYBERSOURCE] fix response field for netcetera authentication response (#8850) chore(events): making events nanosecond level precision (#8759)
Type of Change
Description
add support for partial authorization in payments flow
Implementation
enable_partial_authorizationfield to payments request and include it in the payment_intent tableamount_capturableandamount_capturedpopulated in the connectors flow based on the amount approved in case of partial authorizationsamount_capturableandamount_capturedvalues populated from connector flows and use them to update our payment_intent and payment_attempt tables in post update trackerspartially_authorized_and_requires_captureand attempt status aspartially_authorizedin case of partial authorizationpartially_authorized_and_requires_captureintent status to perform capture operationAPI Changes
enable_partial_authorizationto payments request and responsepartially_authorized_and_requires_captureintent statuspartially_authorizedattempt statusDatabase Changes
enable_partial_authorizationfield to the payment_intent tableAdditional Changes
Motivation and Context
Partial authorization helps minimize the number of declined transactions due to insufficient funds, increasing sales for merchants
How did you test it?
2. Create a partial auth payment (with capture_method = manual) with `worldpayvantiv` connector, perform subsequent capture and refunds with partially approved amount (verify amount_capturable if populated correctly)
a. Create a Payment Intent with `"enable_partial_authorization": "true"` CURLResponse
b. Confirm the payment with following card_details and observe amount_capturable (should be less than total amount)
CURL
Response
c. force_sync the payment, and observe the intent status to be
partially_authorized_and_requires_capturewith partial amount set in amount_capturableCURL
Response
d. Perform capture for amount > amount_capturable which results in error
e. Perform capture for amount <= amount_capturable which results in successful capture and verify if amount_captured is populated as expected
CURL
Response
f. Perform refund for amount <= amount_captured
Create a partial auth payment (with capture_method = automatic) with
worldpayvantivconnector, perform subsequent refund with partially approved amount (verify amount_captured if populated correctly)Perform sanity CIT and MIT payment by sending
enable_partial_authorizationas truePerform sanity Partial Captures
Checklist
cargo +nightly fmt --allcargo clippy