Authorize and Capture Payments
In some scenarios, your checkout process may collect and pre-authorize a purchase before the customer completes checkout. This is useful when you want to run a customer and card against your fraud rules, enable pre-orders, or adjust the final amount at fulfillment.
Both Payment Intents and the direct Payments API support authorize-and-capture. Both approaches result in a Payment object on success.
Getting Started
To get started, you will need a Credova Account.
Get your Secret Key
Next you will need your Secret Key. Go to your Developers section and click Reveal for your Secret Key and copy the value.
Payment Intents
Use capture_method: manual to authorize the card without immediately capturing funds. The intent moves to requires_capture after confirmation and waits up to 7 days for an explicit capture call.
Create a Payment Intent
Call the Create Payment Intent endpoint with capture_method: manual. Including a card at creation time starts the intent in requires_confirmation status:
curl 'https://api.publicsquare.com/payment_intents' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"capture_method": "manual",
"payment_method": {
"card": "card_AjkCFKAYiTsjghXWMzoXFPMxj"
},
"customer": {
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
{
"id": "pmt_int_2xNjK7abcdefghij",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "requires_confirmation",
"amount": 1000,
"currency": "USD",
"capture_method": "manual",
"payment_method": {
"card": {
"id": "card_AjkCFKAYiTsjghXWMzoXFPMxj",
"last_four": "4242",
"brand": "visa",
"exp_month": "12",
"exp_year": "2025"
}
},
"payment_id": null,
"expires_date": "2026-04-16T14:22:10Z",
"created_date": "2026-04-15T14:22:10Z",
"modified_date": "2026-04-15T14:22:10Z"
}
Create Without a Payment Method
For multi-step checkout flows where the payment method is collected separately, omit the payment_method field. The intent starts in requires_payment_method status and can be updated once the card is available:
curl 'https://api.publicsquare.com/payment_intents' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"capture_method": "manual"
}'
Once you have a card, call the Update Payment Intent endpoint to attach it. The intent will transition to requires_confirmation:
curl 'https://api.publicsquare.com/payment_intents/pmt_int_2xNjK7abcdefghij' \
-X 'PUT' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"payment_method": {
"card": "card_AjkCFKAYiTsjghXWMzoXFPMxj"
}
}'
Confirm the Payment Intent
With the intent in requires_confirmation, call the Confirm Payment Intent endpoint to authorize the card. Because capture_method is manual, a successful authorization moves the intent to requires_capture rather than succeeded:
curl 'https://api.publicsquare.com/payment_intents/pmt_int_2xNjK7abcdefghij/confirm' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 3a9f1b72-cc4e-4f92-b7d3-1e5a9c8d2041' \
-H 'Content-Type: application/json'
{
"id": "pmt_int_2xNjK7abcdefghij",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "requires_capture",
"amount": 1000,
"currency": "USD",
"capture_method": "manual",
"payment_id": null,
"expires_date": "2026-04-22T14:22:10Z",
"confirmed_date": "2026-04-15T14:22:45Z",
"created_date": "2026-04-15T14:22:10Z",
"modified_date": "2026-04-15T14:22:45Z"
}
canceled status if not captured before the expires_date.Capture the Payment
Using the authorized intent, call the Capture Payment Intent endpoint:
curl 'https://api.publicsquare.com/payment_intents/pmt_int_2xNjK7abcdefghij/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 7c2e9a41-fd83-4b1e-a5d9-2f6c8b3e1047' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000
}'
You can capture up to, but not exceeding, the original authorized amount. If no amount is passed, the full authorized amount will be captured.
{
"id": "pmt_int_2xNjK7abcdefghij",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "succeeded",
"amount": 1000,
"currency": "USD",
"payment_id": "pmt_5mBpT2ghiklmnopq",
"expires_date": null,
"succeeded_date": "2026-04-17T09:14:22Z",
"created_date": "2026-04-15T14:22:10Z",
"modified_date": "2026-04-17T09:14:22Z"
}
Legacy
The direct Payments API supports authorize-and-capture by passing "capture": false when creating the payment.
For example, given you have a previously collected card:
{
"id": "card_AjkCFKAYiTsjghXWMzoXFPMxj",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"cardholder_name": "John Smith",
"last4": "4242",
"exp_month": "12",
"exp_year": "2025",
"fingerprint": "CC2XvyoohnqecEq4r3FtXv6MdCx4TbaW1UUTdCCN5MNL",
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
}
Create Authorized Payment
We need to make a call to Create Payment endpoint passing "capture": false in the request body:
curl 'https://api.publicsquare.com/payments' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPONTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"amount": 1000,
"currency": "USD",
"capture": false,
"payment_method": {
"card": "card_AjkCFKAYiTsjghXWMzoXFPMxj"
},
"customer": {
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
}
}'
Authorized Payment Response
You should see a payment response with a requires_capture status similar to:
{
"id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "requires_capture",
"transaction_id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"amount": 0,
"amount_charged": 0,
"amount_capturable": 1000,
"amount_refunded": 0,
"refunded": false,
"currency": "USD",
"payment_method": {
"card": {
"id": "card_AjkCFKAYiTsjghXWMzoXFPMxj",
"cardholder_name": "John Smith",
"last4": "4242",
"exp_month": "12",
"exp_year": "2025",
"brand": "visa",
"avs_code": "Y",
"cvv2_reply": "M",
"fingerprint": "CC2XvyoohnqecEq4r3FtXv6MdCx4TbaW1UUTdCCN5MNL"
}
},
"customer": {
"id": "cus_7Ay5mcUXAxwrN6wQEQUVEHBCJ",
"first_name": "John",
"last_name": "Smith",
"email": "john.smith@email.com"
},
"billing_details": {
"address_line_1": "111 Test St.",
"city": "Des Moines",
"state": "IA",
"postal_code": "51111",
"country": "US"
},
"transaction": {
"id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "requires_capture",
"amount": 1000,
"fee_amount": 0,
"net_amount": 1000,
"currency": "USD",
"type_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"type": "payment",
"processor": "nuvei",
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
},
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
}
If the payment authorization was declined by the processor or rejected because of fraud decisioning rules, you will see a payment status of rejected or declined. These payments cannot be captured.
Capture the Payment
Using the authorized payment from the previous step, we now need to make a call to Capture Payment endpoint:
curl 'https://api.publicsquare.com/payments/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'Content-Type: application/json' \
-d '{
"payment_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"amount": 1000
}'
You can capture up to, but not exceeding, the original authorized payment amount. If no amount is passed, the full authorized amount of the payment will be captured.
Captured Payment Response
You should see a payment response with a succeeded status similar to:
{
"id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "succeeded",
"transaction_id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"amount": 1000,
"amount_charged": 1000,
"amount_capturable": 0,
...
"transaction": {
"id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "succeeded",
"amount": 1000,
"fee_amount": 0,
"net_amount": 1000,
"processor": "nuvei",
"processor_id": "7110000000010554769",
...
},
...
}
Multiple partial captures
Instead of capturing the full authorized amount in a single call, you can capture an authorization in multiple, smaller captures. This is useful when the final amount is not known up front, such as shipment-based fulfillment or usage-based billing.
Interim captures
Call the capture endpoint with is_final: false and an amount less than the remaining capturable amount. The authorization stays open so you can capture again later.
is_final defaults to true. Pass is_final: false explicitly on every interim capture, or the authorization closes out early.Using a payment intent:
curl 'https://api.publicsquare.com/payment-intents/pmt_int_2xNjK7abcdefghij/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 7c2e9a41-fd83-4b1e-a5d9-2f6c8b3e1047' \
-H 'Content-Type: application/json' \
-d '{
"amount": 400,
"is_final": false
}'
Using the legacy endpoint:
curl 'https://api.publicsquare.com/payments/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 09ec2c87-7fb8-44ca-bb18-5c71a76974da' \
-H 'Content-Type: application/json' \
-d '{
"payment_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"amount": 400,
"is_final": false
}'
IDEMPOTENCY-KEY header on every capture request, including interim ones, so a retried request cannot create a duplicate capture.While an authorization has open interim captures, the payment status is partially_captured. The payment intent's own status stays requires_capture — only the nested payment reports partially_captured.
Final capture
A capture is final when any of the following is true:
- You omit
is_final, or passis_final: true.is_finaldefaults totrue. - You send
amount: 0. This always releases the remaining authorization, regardless ofis_final. - The
amountyou send equals the full remaining capturable amount.
A final capture completes the payment: status moves to succeeded and the remaining authorization is released.
curl 'https://api.publicsquare.com/payment-intents/pmt_int_2xNjK7abcdefghij/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 3a9f1b72-cc4e-4f92-b7d3-1e5a9c8d2041' \
-H 'Content-Type: application/json' \
-d '{
"amount": 600,
"is_final": true
}'
Releasing the remaining authorization
To release the remaining authorization without capturing more funds, send amount: 0. This always releases the remainder, whether or not you also pass is_final. This is supported where the account/processor supports it.
curl 'https://api.publicsquare.com/payments/capture' \
-X 'POST' \
-H 'X-API-KEY: <SECRET_API_KEY>' \
-H 'IDEMPOTENCY-KEY: 5b6e1c93-2a7d-4f8e-9c1b-3d7a8f2e6b10' \
-H 'Content-Type: application/json' \
-d '{
"payment_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"amount": 0
}'
Capturing more than the remaining capturable amount is also rejected: 'amount' exceeds capturable payment amount.
The payment_captures array
Every payment response, including the payment nested in a payment-intent response, includes a payment_captures array. Entries are ordered oldest first. Payments with no captures yet have an empty array, and payments captured before this feature shipped show a single entry.
{
"id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"status": "partially_captured",
"transaction_id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"amount_charged": 400,
"amount_capturable": 600,
"amount_refunded": 0,
"refunded": false,
"currency": "USD",
"payment_captures": [
{
"id": "cpt_3fRkT8bcdefghijklmnop",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"external_id": null,
"amount": 400,
"status": "succeeded",
"payment_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"transaction_id": "trx_95rvMJvAVeG68W4NtLdfkN3LG",
"currency": "USD",
"is_final": false,
"declined_reason": null,
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:02:29.212Z"
},
{
"id": "cpt_7hQmV1defghijklmnopqr",
"account_id": "acc_B518niGwGYKzig6vtrRVZGGGV",
"environment": "test",
"external_id": null,
"amount": 200,
"status": "pending",
"payment_id": "pmt_2YKewBonG4tgk12MheY3PiHDy",
"transaction_id": "trx_51xzQKvBWfH79Y5OuMegfP4MH",
"currency": "USD",
"is_final": false,
"declined_reason": null,
"created_at": "2024-06-30T01:04:11.500Z",
"modified_at": "2024-06-30T01:04:11.500Z"
}
],
"created_at": "2024-06-30T01:02:29.212Z",
"modified_at": "2024-06-30T01:04:11.500Z"
}
Each payment_captures entry has the following fields:
| Field | Description |
|---|---|
id | Unique identifier for the capture. Prefix: cpt_. |
account_id | The merchant account that owns the capture. |
environment | test or production. |
external_id | Optional external identifier you passed on the capture request. |
amount | Amount captured, in cents. |
status | One of pending, succeeded, declined, error, cancelled. |
payment_id | ID of the parent payment. |
transaction_id | ID of the parent transaction. |
currency | Three-character ISO currency code. |
is_final | Whether this capture was final. |
declined_reason | Populated when status is declined. |
created_at | ISO 8601 timestamp. |
modified_at | ISO 8601 timestamp. |
An optional external_id and IDEMPOTENCY-KEY header can both be passed on each capture request.
Maximum captures per authorization
Each authorization allows a limited number of captures, controlled by the account setting max_captures_per_authorization (default 5). A capture beyond the limit is rejected with a 400 error: payment has reached the maximum of {n} captures. Contact PublicSquare support if you need this limit adjusted for your account.
'american_express' does not support partial payment capture. This error is returned unless the capture amount equals the full capturable amount.Conclusion
Authorize and capturing payments also works with ACH payments using a bank account payment method. See our Process ACH payments guide to see how to collect bank accounts and process ACH payments following similar steps in this guide.
Now that we have seen how to authorize and capture payments with a collected card, we may need to manage the payment or view information about the payment. Follow these guides to learn more: