Hold then capture
How to authorize a card hold and capture only when you're ready to charge.
Overview
Hold Then Capture splits a card transaction into two steps: authorization (reserving the funds) and capture (actually charging). You place a hold when the customer checks out, then capture once you're ready to fulfill — up to 7 days later. If you cancel instead, no charge is made.
Available for Visa and Mastercard only. Account activation is required — contact [email protected] to enable it. Shopify merchants with the Credit/Debit Card via PayMongo plugin can enable it directly from the Shopify admin.
Hold a payment
Create a Payment Intent with capture_type set to "manual". The rest of the flow — creating a Payment Method and attaching it — is the same as a standard card payment.
const intent = await fetch('https://api.paymongo.com/v1/payment_intents', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('sk_test_YOUR_SECRET_KEY:')
},
body: JSON.stringify({
data: {
attributes: {
amount: 50000,
currency: 'PHP',
payment_method_allowed: ['card'],
capture_type: 'manual',
description: 'Order #9012'
}
}
})
}).then(r => r.json());After the customer completes 3D Secure authentication, the Payment Intent moves to awaiting_capture. Funds are reserved on the customer's card but not yet charged.
The hold expires automatically after 7 days. Expired holds release the reserved funds back to the customer and cannot be captured — you must restart the payment flow if this happens.
Capture a payment
When you're ready to charge, call the capture endpoint. You can capture the full amount or a partial amount — set amount in the request body to capture less than the Payment Intent amount. If no amount is specified, the full amount is captured.
await fetch(`https://api.paymongo.com/v1/payment_intents/${intentId}/capture`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa('sk_test_YOUR_SECRET_KEY:')
},
body: JSON.stringify({
data: {
attributes: {
amount: 50000 // omit to capture full amount
}
}
})
}).then(r => r.json());To void the hold instead of charging, call the cancel endpoint:
await fetch(`https://api.paymongo.com/v1/payment_intents/${intentId}/cancel`, {
method: 'POST',
headers: {
'Authorization': 'Basic ' + btoa('sk_test_YOUR_SECRET_KEY:')
}
}).then(r => r.json());The PayMongo dashboard shows held payments under three tabs: Hold, Captured, and Returned. Holds expiring within 2 days are flagged as Expiring Soon.
Updated about 4 hours ago