Skip to main content

Authorization & Capture

An authorization reserves funds on a customer's card without capturing (charging) them immediately. You capture — or "settle" — the funds later, once you are ready to fulfill. You can also release the hold entirely by voiding the authorization.

When to use auth & capture​

ScenarioWhy auth & capture
Hotel or rental holdsReserve the full amount at booking; settle the actual charge at checkout
Marketplace escrowHold buyer funds until the seller confirms delivery
Delayed fulfillmentAuthorize at order time; capture only when the item ships
Partial captureAuthorize for an estimated total; settle the exact amount actually used

Path A: Authorization via card UI​

Use this path when the customer is present and will enter their card details in the hosted checkout form. The flow is identical to a regular card checkout — only the SDK method names differ.

Step 1: Start an authorization session (server)​

import AccruPay, { 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({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
data: {
merchantInternalTransactionCode: 'auth-txn-001',
amount: 15000n, // $150.00 hold
currency: CURRENCY.USD,
storePaymentMethod: false,
customer: {
merchantInternalCustomerCode: 'customer-123',
},
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});

// Send only session.id to the frontend
return session.id;

Step 2: Render the checkout form (React)​

The React SDK form is identical to the card checkout form — use the same components:

import {
AccruPay,
CardholderName,
CardNumber,
CardExpiry,
CardCVC,
SubmitButton,
} from '@accrupay/react';

function AuthorizationForm({ sessionId }: { sessionId: string }) {
return (
<AccruPay
merchantPublicId={process.env.NEXT_PUBLIC_ACCRUPAY_MERCHANT_ID!}
transactionSessionId={sessionId}
>
<CardholderName placeholder="Full name on card" />
<CardNumber />
<CardExpiry />
<CardCVC />
<SubmitButton
onSuccess={(result) => console.log('Authorized', result)}
onError={(err) => console.error('Authorization failed', err)}
>
Authorize $150.00
</SubmitButton>
</AccruPay>
);
}

Step 3: Verify the authorization (server)​

Use any one of these identifiers to look up the result:

const transaction =
await sdk.transactions.clientSessions.authorizations.verify({
merchantInternalTransactionCode: 'auth-txn-001',
// Alternatively: id, providerCode, or token
});

console.log(transaction.id, transaction.status);

Path B: Authorization via stored card (server-only)​

Use this path when the customer's card is already stored and no frontend interaction is needed.

Step 1: Start the authorization (server)​

const session =
await sdk.transactions.serverSessions.authorizations.paymentMethod.start({
merchantTransactionProviderId: process.env.ACCRUPAY_PROVIDER_ID,
data: {
merchantInternalTransactionCode: 'auth-stored-001',
merchantCustomerPaymentMethodId: 'pm_abc123',
amount: 15000n, // $150.00 hold
currency: CURRENCY.USD,
billing: {
billingFirstName: 'Jane',
billingLastName: 'Smith',
billingEmail: 'jane@example.com',
billingAddressCountry: COUNTRY_ISO_2.US,
},
},
});

Step 2: Verify the authorization (server)​

For server-session authorizations, you can identify the transaction by id, merchantInternalTransactionCode, or providerCode. There is no token option for server-side flows.

const transaction =
await sdk.transactions.serverSessions.authorizations.paymentMethod.verify({
merchantInternalTransactionCode: 'auth-stored-001',
// Alternatively: id or providerCode
});

Capture (settle)​

When you are ready to charge the customer, call settle(). You must always supply the amount — even if you want to capture the full authorized amount.

const settled = await sdk.transactions.authorizations.settle({
merchantInternalTransactionCode: 'auth-txn-001',
amount: 12000n, // $120.00 — partial capture
});
amount is required

There is no shorthand to capture "the full authorized amount." You must always pass amount explicitly to settle(). Omitting it will result in an error.

Partial capture: pass an amount less than or equal to the original authorized amount. The remaining hold is released automatically — behavior confirmed for current supported providers; confirm with your provider for others.

You can identify the authorization using any of:

IdentifierType
idstring
merchantInternalTransactionCodestring
providerCodestring

Release hold (void)​

To release the authorization without charging the customer, call void():

await sdk.transactions.authorizations.void({
merchantInternalTransactionCode: 'auth-txn-001',
// Alternatively: id or providerCode
});

Voiding immediately cancels the hold. The reserved funds are returned to the customer's available balance, subject to the card network's release timing.


Provider capture windows​

After the capture window closes, the authorization expires and the hold is released automatically. A settle() call after expiry will fail — you must re-authorize the customer.

⬡Capture window by provider
Nuvei

7 days from authorization.

Stripe

7 days from authorization. Stripe cancels uncaptured PaymentIntents automatically after this window.

Other providers

Capture windows range from 1 day to 30 days depending on the PSP and card network. Check your provider's documentation for the exact limit.

warning

Treat the capture window as a hard deadline. Build a scheduled job or alerting on any authorization older than 80% of your provider's window to catch and settle or void before expiry.


Next steps​