Authorize and capture
A two-step payment: first authorize the card to reserve funds, then capture to settle them. Use this when you need to confirm funds are available before you commit the charge, such as verifying an order before shipping.
The key difference from a standard sale: set type: "authorize" instead of "sale". The authorization reserves funds without taking them. You capture later by creating a second transaction with type: "sale".
Flow overview
Authorize and capture builds on top of a paymentInstrumentId already attached to a customer. Tokenization is a prerequisite step that differs between environments and integration paths. The authorize and capture calls themselves are identical across paths once you have the paymentInstrumentId.
Stage flow
On stage there is no production tokenization host. Tokenize the card through the staging tokenization endpoint, attach the token to the customer, then run authorize and capture.
See Tokenization endpoint for the stage body shape.
Production flow — FramePay
For web integrations on production, the recommended path is FramePay. Card data is collected by hosted iframe fields, never touches your server, and your PCI scope stays at SAQ A.
See FramePay for the SDK integration.
Production flow — server-side tokenization endpoint
For native mobile apps or backend-only integrations on production, the card data is tokenized through the dedicated production tokenization host (tokenization.payments.ai). Raw card data flows through your server, placing your PCI scope at SAQ D.
See When to use FramePay vs server-side for the choice between paths and Tokenization endpoint for the production body shape.
Prerequisites
- A customer with an attached payment instrument. See Create customer with payment instrument.
- The customer's
paymentInstrumentId.
Set your environment variables first. The POST /transactions endpoint sits under the Public API, so the host is staging-api.payments.ai on stage and api.payments.ai on production. Tokenization (the step that produces the paymentInstrumentId) does not share this host pattern — stage and production tokenization use different hosts, paths, and request body shapes. See the Flow overview above for the three integration paths and Tokenization endpoint for the body differences between environments.
Stage:
export API_HOST="staging-api.payments.ai"
export API_KEY="Your API Key Here"
export ORGANIZATION_ID="Your Organization ID Here"
export CUSTOMER_ID="Customer ID Here"
Production:
export API_HOST="api.payments.ai"
export API_KEY="Your API Key Here"
export ORGANIZATION_ID="Your Organization ID Here"
export CUSTOMER_ID="Customer ID Here"
The curl examples below use ${API_HOST} because POST /transactions shares one structure across environments — only the host changes. This is not the case for the tokenization step.
1. Get the payment instrument id
curl -X GET \
"https://${API_HOST}/v1/public-api/organizations/${ORGANIZATION_ID}/customers/${CUSTOMER_ID}/payment-instruments" \
--header "Content-Type: application/json" \
--header "Authorization: ApiKey ${API_KEY}"
2. Authorize the transaction
Setting type: "authorize" reserves funds without capturing them. Note the transaction id from the response because you need it to track the authorization.
curl -X POST \
"https://${API_HOST}/v1/public-api/organizations/${ORGANIZATION_ID}/transactions" \
--header "Content-Type: application/json" \
--header "Authorization: ApiKey ${API_KEY}" \
--data-raw '{
"type": "authorize",
"customerId": "Customer ID Here",
"currency": "USD",
"amount": 1,
"paymentInstruction": {
"paymentInstrumentId": "PaymentInstrumentID Here"
}
}'
3. Capture the transaction
To settle the reserved funds, create a new transaction with type: "sale" using the same customerId and paymentInstrumentId.
curl -X POST \
"https://${API_HOST}/v1/public-api/organizations/${ORGANIZATION_ID}/transactions" \
--header "Content-Type: application/json" \
--header "Authorization: ApiKey ${API_KEY}" \
--data-raw '{
"type": "sale",
"customerId": "Customer ID Here",
"currency": "USD",
"amount": 1,
"paymentInstruction": {
"paymentInstrumentId": "PaymentInstrumentID Here"
}
}'
Authorization expiry
The issuing bank holds reserved funds for a limited window set by the card scheme. If you do not capture within the window, the hold expires automatically and the funds are released back to the customer. Typical card-scheme defaults:
| Scheme | Typical hold window |
|---|---|
| Visa | ~7 days |
| Mastercard | ~30 days |
| American Express | ~7 days |
| Discover | ~10 days |
These are card-scheme defaults rather than PaymentsAI rules. The actual window depends on the issuing bank and merchant category. Treat them as planning guidance, not contractual guarantees. If you need to release an authorization before its window expires, contact your Integration Consultant, as the public API does not currently expose a void endpoint.
Capture amount
The merchant guide and PaymentsAI's documented flow show the capture (sale) amount matching the original authorization. Partial capture (capturing less than the authorized amount and releasing the difference) is not currently documented for the public API. If you need it, confirm the behavior with your Integration Consultant before relying on it.
Notes
- The
customerIdandpaymentInstrumentIdon the capture call must match the original authorization. PaymentsAI does not let you capture an authorization against a different payment instrument. - A successful authorize returns
status: "waiting". A successful capture returnsstatus: "completed". The original authorize transaction stays on record alongside the capture.