Capture a payment multiple times
Capture a PaymentIntent multiple times, up to the authorized amount.
Multicapture allows you to capture a PaymentIntent multiple times for a single authorization, up to the full amount of the PaymentIntent. You can use it when you have orders with multiple shipments, and want to capture funds as you fulfill parts of the order.
IC+ feature
Multicapture is part of the functionality we offer to users on IC+ pricing. If you’re on blended Stripe pricing and want access to this feature, contact Stripe Support.
Availability
When using multicapture, be aware of the following restrictions:
- Multicapture is only supported for online card payments
- Only available with Amex, Visa, Discover, Mastercard, and Cartes Bancaires
- Separate charges and transfers fund flows using source_transaction aren’t supported
- Stripe allows you to capture up to 50 times for a single PaymentIntent
Best practices
Where sending separate shipments for one order, proactively notify your end customer with the details of each shipment to avoid inquiries and chargebacks from customers because of confusion with seeing multiple transactions on their bank statement. Here are some best practices for doing so:
- Inform the customer of the estimated delivery date and transaction amount for each shipment at the time of checkout, before purchase.
- Notify your customer upon each shipment, along with the transaction amount.
- Disclose your full refund and cancellation policy.
These best practices might be required under applicable network rules, depending on the network.
Compliance
You’re responsible for your compliance with all applicable laws, regulations, and network rules when using multicapture. Consult the rules for the card networks that you want to use this feature with to make sure your sales comply with all applicable rules, which vary by network. For example, most card networks restrict multicapture usage to card-not-present transactions for the sale of goods that ship separately. Certain card networks permit multicapture for businesses based on their industry (for example, travel), while some don’t permit multicapture for installment or deposit workflows.
The information provided on this page relating to your compliance with these requirements is for your general guidance, and isn’t legal, tax, accounting, or other professional advice. Consult with a professional if you’re unsure about your obligations.
Create and confirm an uncaptured PaymentIntent
To indicate that you want separate authorization and capture, specify the capture_method as manual
when creating the PaymentIntent. To learn more about separate authorization and capture, see how to place a hold on a payment method.
Use the if_
or never
parameters to request multicapture for this payment.
if_
: The created PaymentIntent will allow multiple captures, if the payment method supports it.available never
: The created PaymentIntent won’t allow for multiple captures
In the response, the payment_
field on the latest_charge contains available
or unavailable
based on the customer’s payment method.
// PaymentIntent Response { "id": "pi_xxx", "object": "payment_intent", "amount": 1000, "amount_capturable": 1000, "amount_received": 0, ... // if latest_charge is expanded "latest_charge": { "id": "ch_xxx", "object": "charge", "amount": 1000, "amount_captured": 0, "amount_refunded": 0, "payment_method_details": { "card": { "multicapture": { "status": "available" // or "unavailable" } } } ... } ... }
Capture the PaymentIntent
For a PaymentIntent in a requires_capture state where multicapture is available
, specifying the optional final_
parameter to be false
tells Stripe not to release the remaining uncaptured funds when calling the capture API. For example, if you confirm a 10 USD payment intent, capturing 7 USD with final_
keeps the remaining 3 USD authorized.
In the PI capture response, the amount_capturable and amount_received fields update accordingly.
// PaymentIntent Response { "id": "pi_ANipwO3zNfjeWODtRPIg", "object": "payment_intent", "amount": 1000, "amount_capturable": 300, // 1000 - 700 = 300 "amount_received": 700, // if latest_charge is expanded "latest_charge": { "id": "ch_xxx", "object": "charge", "amount": 1000, "amount_captured": 700, "amount_refunded": 0, ... } ... }
Final capture
The PaymentIntent remains in a requires_
state until you do one of the following:
- Set
final_
tocapture true
- Make a capture without the
final_
parameter (becausecapture final_
defaults tocapture true
) - The authorization window expires.
At this point, Stripe releases any remaining funds and transitions the PaymentIntent to a succeeded
state.
In the PI capture response, the amount_capturable and amount_received fields will be updated accordingly.
// PaymentIntent Response { "id": "pi_ANipwO3zNfjeWODtRPIg", "object": "payment_intent", "amount": 1000, "amount_capturable": 0, // not 100 due to final_capture=true "amount_received": 900, // 700 + 200 = 900 // if latest_charge is expanded "latest_charge": { "id": "ch_xxx", "object": "charge", "amount": 1000, "amount_captured": 900, "amount_refunded": 0, ... } ... }
Uncaptured PaymentIntents transition to canceled
, while partially captured PaymentIntents transition to succeeded
.
Test your integration
Use a Stripe test card with any CVC, postal code, and future expiration date to test multicapture payments.
Number | Payment Method | Description |
---|---|---|
pm_ | This test card support multicapture. | |
pm_ | Cartes Bancaires/Visa test card which supports multicapture. |
Refunds
For a PaymentIntent in requires_
state, you can refund any number of times up to the total captured amount minus the total refunded amount, which is the amount_received - amount_refunded. The charge.refunded field transitions to true only when the final capture has been performed and the entire amount_received is refunded.
Stripe doesn’t support partial refunds with refund_application_fee=true or reverse_transfer=true. Instead, you can perform partial fee refunds by manually performing partial fee refunds and transfer reversals using the application fee refund and transfer reversal endpoints. After using the application fee refund or transfer reversal endpoints, Stripe doesn’t support any further refunds with refund_application_fee=true or reverse_transfer=true respectively.
Connect
Multicapture supports all Connect use cases, with the exception of Separate Charges and Transfers with the source_transaction parameter. The application_fee_amount and transfer_data[amount] parameters have some additional validations. Consider the following validations when implementing multicapture with Connect:
- Setting
application_
orfee_ amount transfer_
on the first capture makes it required for all subsequent captures. Eachdata[amount] application_
andfee_ amount transfer_
passed at capture time overrides the values passed in on PaymentIntent creation, confirmation, and update.data[amount] - Stripe doesn’t support partial refunds on multicapture payments with refund_application_fee=true or reverse_transfer=true. You can perform partial fee refunds or transfer reversals using the application fee refund and transfer reversal endpoints.
Webhooks
Charge updated webhooks
We send a charge.updated webhook each time you capture a payment.
For example, on the first capture of a destination charge multicapture payment with an application_
, we update these fields from empty to non-empty values.
// charge.updated { "data": { "id": "ch_xxx", "object": "charge", "amount": 1000, "balance_transaction": "txn_xxx", // applicable to all charges "transfer": "tr_xxx", // applicable to destination charges only "application_fee": "fee_xxx", // applicable to Connect only ... }, "previous_attributes": { "balance_transaction": null, // applicable to all charges "transfer": null, // applicable to destination charges only "application_fee": null, // applicable to Connect only } }
payment_intent.amount_capturable_updated
We send payment_intent.amount_capturable_updated on every capture, regardless of amount_to_capture and final_capture values.
For example, if we capture 1 USD from a PaymentIntent with an amount of 10 USD, the PaymentIntent’s amount_capturable field updates to 9 USD.
// payment_intent.amount_capturable_updated { "data": { "id": "pi_xxx", "object": "payment_intent", "amount": 1000, "amount_capturable": 900 // 1000 - 100 = 900 ... }, "previous_attributes": { "amount_capturable": 1000 } }
Charge captured events
We send a charge.captured event for final captures or at the end of the authorization window to reverse the authorization of the uncaptured amount. The captured field for a charge only becomes true
after a final capture or authorization reversal.
For example, if we do a capture with amount=0
and final_
, the captured attribute on the charge changes from false to true.
// charge.captured { "data": { "id": "ch_xxx", "object": "charge", "captured": true ... }, "previous_attributes": { "captured": false } }
Refund webhooks
Multicapture refund webhooks are no different than non-multicapture refund webhooks.
During each partial refund, we’ll send a charge.refunded event. For connected accounts, we’ll additionally send application_fee.refunded events when we refund application fees and transfer.reversed events when we reverse transfers.