Capture Payment
POST/payments/:paymentId/captureDescription
Capture an authorized payment transferring funds to your settlement address. This endpoint is only available for payments created with payment_method: "two_step".
Requires a signed request to authorize the fund movement.
Your signature is verified before the capture executes. Use signCapture() from the @exodus/checkout-signer SDK. Like every merchant signature, it is EIP-712 typed data.
Headers
| Header | Description | Required |
|---|---|---|
| Authorization | Bearer token with your API key | yes |
| Content-Type | application/json | yes |
| X-Signature | Signature from signCapture(), signed with your signing key. | yes |
Path Parameters
| Name | Type | Description | Required |
|---|---|---|---|
| paymentId | string | The unique identifier of the payment to capture. | yes |
Request Body
| Name | Type | Description | Required |
|---|---|---|---|
| deadline | number | Unix timestamp (seconds) the capture signature commits to. Must equal the `deadline` returned by `signCapture`. The token and amount are bound into the signature rather than sent here; the server derives them from the escrowed payment. | yes |
Example Request
import { CheckoutSigner } from '@exodus/checkout-signer'
const signer = new CheckoutSigner()
// paymentId: system identifier for the payment (used in the URL path)
const paymentId = 'tz4a98xxat96iws9zmbrgj3a'
// Fetch the payment (or use the payment.escrow_confirmed webhook object as-is)
const payment = await fetch(
`https://checkout-api.exodus-int.com/payments/${paymentId}`,
{ headers: { Authorization: 'Bearer sk_live_xxxxxxxxxxxxxxxx' } },
).then((r) => r.json())
// Pass the payment straight in — chain, token, amount, and deadline are handled for you
const { signature, body } = signer.signCapture(payment)
const response = await fetch(
`https://checkout-api.exodus-int.com/payments/${paymentId}/capture`,
{
method: 'POST',
headers: {
Authorization: 'Bearer sk_live_xxxxxxxxxxxxxxxx',
'Content-Type': 'application/json',
'X-Signature': signature,
},
body: JSON.stringify(body),
},
)Response
{
"id": "tz4a98xxat96iws9zmbrgj3a",
"on_chain_id": "0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b",
"status": "settled",
"tx_hash": "0x8a9c67b2d1e3f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9"
}Error Responses
{
"error": {
"type": "invalid_request",
"message": "Capture is only available for two-step payments"
}
}{
"error": {
"type": "authentication_error",
"message": "Invalid signature"
}
}{
"error": {
"type": "invalid_request",
"message": "Payment has already been fully captured"
}
}Captures run a compliance screen before releasing funds. If the screen blocks the payment or the
screening provider is temporarily unavailable, the API returns 422 with error.type: "cannot_process".
{
"error": {
"type": "cannot_process",
"message": "Payment cannot be processed",
"code": "flagged",
"data": { "payment_id": "tz4a98xxat96iws9zmbrgj3a" }
}
}error.code is flagged when the payment is permanently blocked, or screening_pending when the screening provider is temporarily unavailable (retry later).
