Skip to main content

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.

You need a saved card for this guide. Save one with Save Cards, from your web app or from your servers. Either way you get a card id that starts with card_.

Before you start​

Credova account
Sign up or sign in to the Credova Portal.
Secret Key
Authenticates requests from your server. Never send it to the browser.

Authorize and Capture​

You can authorize and capture with either Payment Intents or the direct Payments API. Select the tab for the API you use.

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:

Create a Payment Intent with Manual Capture
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"
}
}'
The amount is provided in cents. 1000 is the equivalent of $10.00
Create Response
{
"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:

Create a Payment Intent without a Payment Method
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:

Attach a Payment Method
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:

Confirm a Payment Intent
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'
Confirm Response
{
"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"
}
The authorization expires after 7 days. The intent will automatically move to canceled status if not captured before the expires_date.

Capture the Payment​

Using the authorized intent, call the Capture Payment Intent endpoint:

Capture 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": 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.

Capture Response
{
"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"
}

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.

Not all payment processors support multiple partial captures. If your account's processor does not support it, a second capture on the same authorization is rejected.

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:

Capture a Payment Intent (interim)
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:

Capture a Payment (interim)
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
}'

Send a unique IDEMPOTENCY-KEY header on every capture request, including interim ones. A retried request then 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 pass is_final: true. is_final defaults to true.
  • You send amount: 0. This always releases the remaining authorization, regardless of is_final.
  • The amount you send equals the full remaining capturable amount.

A final capture completes the payment: status moves to succeeded and the remaining authorization is released.

Final Capture 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: 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.

Release Remaining Authorization
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.

Payment with Multiple Captures
{
"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:

FieldDescription
idUnique identifier for the capture. Prefix: cpt_.
account_idThe merchant account that owns the capture.
environmenttest or production.
external_idOptional external identifier you passed on the capture request.
amountAmount captured, in cents.
statusOne of pending, succeeded, declined, error, cancelled.
payment_idID of the parent payment.
transaction_idID of the parent transaction.
currencyThree-character ISO currency code.
is_finalWhether this capture was final.
declined_reasonPopulated when status is declined.
created_atISO 8601 timestamp.
modified_atISO 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 support if you need this limit adjusted for your account.

American Express does not support partial capture: 'american_express' does not support partial payment capture. This error is returned unless the capture amount equals the full capturable amount.

Amount Fields​

A payment reports four amounts. They all use the smallest currency unit, so 1000 is $10.00 USD.

FieldMeaning
amountThe amount you requested when you created the payment. It does not change
amount_capturableThe authorized amount you can still capture
amount_chargedThe amount captured so far. This is the amount the customer pays
amount_refundedThe amount refunded so far

After an authorization, amount_charged is 0 and amount_capturable holds the full amount. After a capture, the captured value moves to amount_charged and amount_capturable drops by the same value.

A partial capture leaves the rest in amount_capturable, so a second capture can take it.

To know what the customer paid, read amount_charged. Do not read amount, which only records what you asked for.

Conclusion​

Authorize and capturing payments also works with ACH payments using a bank account payment method. See Save Bank Accounts to collect bank accounts and Accept Bank Account Payments to process ACH payments in similar steps.

Now that we have seen how to authorize and capture payments with a saved card, we may need to manage the payment or view information about the payment. Follow these guides to learn more: