Authorization & Capture
Authorization and capture is a two-phase payment model. An authorization places a hold on funds without moving money. A capture (called a settle in AccruPay) completes the transfer. Between those two events, you can inspect the hold, partially capture it, or release it entirely.
When to use it
| Use case | Why auth + capture fits |
|---|---|
| Hotels and rentals | Auth at booking; capture the final amount at checkout, which may differ from the original hold. |
| Marketplaces | Auth when a buyer commits; capture only after the seller confirms fulfillment. |
| Delayed shipment | Auth at order placement; capture when goods ship, staying within the provider's capture window. |
| Variable-amount orders | Auth for an estimated max; capture the exact amount once it is known. |
Authorization flows
Via card UI (client session)
The customer enters their card details in the React SDK checkout — identical to a regular payment flow, but using the authorizations namespace.
Server: start the authorization session
import AccruPay, { TRANSACTION_PROVIDER, CURRENCY, COUNTRY_ISO_2 } from '@accrupay/node';
const sdk = new AccruPay({ apiSecret: process.env.ACCRUPAY_API_SECRET });
const session = await sdk.transactions.clientSessions.authorizations.start({
transactionProvider: TRANSACTION_PROVIDER.YOUR_PROVIDER,
data: {
amount: 20000n,
currency: CURRENCY.USD,
merchantInternalCustomerCode: 'customer-123',
merchantInternalTransactionCode: 'auth-456',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});
// Send session.id to your frontend
Frontend: render the checkout
import { AccruPay, CardNumber, CardExpiry, CardCVC, SubmitButton } from '@accrupay/react';
function AuthForm({ sessionId }: { sessionId: string }) {
return (
<AccruPay
merchantPublicId="your-merchant-public-id"
transactionSessionId={sessionId}
>
<CardNumber />
<CardExpiry />
<CardCVC />
<SubmitButton>Authorize $200.00</SubmitButton>
</AccruPay>
);
}
Server: verify the authorization
const transaction = await sdk.transactions.clientSessions.authorizations.verify({
id: session.id,
});
// Store transaction.id — you need it to settle or void later
Via stored payment method (server session)
If the customer already has a stored payment method, the entire flow is server-side.
// Start a server-side authorization session
const session = await sdk.transactions.serverSessions.authorizations.paymentMethod.start({
transactionProvider: TRANSACTION_PROVIDER.YOUR_PROVIDER,
data: {
merchantCustomerPaymentMethodId: 'payment-method-id',
amount: 20000n,
currency: CURRENCY.USD,
merchantInternalCustomerCode: 'customer-123',
merchantInternalTransactionCode: 'auth-789',
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});
const transaction = await sdk.transactions.serverSessions.authorizations.paymentMethod.verify({
id: session.id,
});
Capturing funds (settle)
Call settle() to capture the authorized amount and move funds. You must always pass an explicit amount.
// Full capture — settle the full authorized amount
const settled = await sdk.transactions.authorizations.settle({
id: transaction.id,
data: {
amount: 20000n, // must match or be less than the authorized amount
},
});
Partial capture
Settle with an amount less than what was authorized. The remaining hold is released automatically.
// Partial capture — charge only $150 of the $200 hold
const settled = await sdk.transactions.authorizations.settle({
id: transaction.id,
data: {
amount: 15000n, // $50 hold is released
},
});
settle() requires you to pass amount explicitly. There is no "capture full amount" shorthand — omitting amount is a validation error.
Releasing the hold (void)
Call void() to cancel the authorization and release the full hold. No funds move.
await sdk.transactions.authorizations.void({
id: transaction.id,
});
Status transitions
Auth transaction: PENDING → SUCCEEDED (approved, funds on hold)
├─ settle() → new SETTLE transaction → SUCCEEDED
└─ void() → auth transaction → CANCELED
| Outcome | Transaction status | Notes |
|---|---|---|
| Authorization approved | SUCCEEDED | Funds reserved, not yet captured |
| Captured (settled) | SUCCEEDED (new SETTLE transaction) | settle() creates a separate child transaction |
| Hold released | CANCELED (original auth transaction) | void() cancels the hold with no charge |
The original authorization transaction moves to CANCELED after a void, or remains SUCCEEDED indefinitely after a successful settle (the settle creates its own separate transaction record).
Provider capture windows
All providers enforce a maximum window between authorization and capture. After this window closes, the hold expires automatically and any subsequent settle() call will fail at the provider level. Void the transaction and create a fresh authorization if needed.
7 days from authorization. Authorizations not settled or voided within this window are automatically released by Nuvei.
7 days from authorization. Uncaptured PaymentIntents expire after 7 days and Stripe releases the hold automatically.
Capture windows vary significantly — from 1 day to 30 days depending on the PSP and card network rules. Consult your payment provider's documentation for the exact limit before designing your capture flow.