Sent as a checkout is charged, paid, fails or expires.
checkout-status-changed follows a checkout from the first charge attempt to its outcome. Use it to fulfil an order when the buyer has paid.
When it fires
For checkouts you create with Create Checkout:
- A charge attempt starts, whether the buyer pays or you charge with Charge Checkout.
- The checkout moves to
PROCESSING,PAID,FAILEDorUNKNOWN. - The checkout expires (
EXPIRED).
A single charge attempt usually sends several deliveries, and some carry the same status. Always act on data.status.
It does not fire for the checkouts that bill a subscription. Follow those with subscription-status-changed and subscription-payment-status-changed.
What to do
data.status | Suggested action |
|---|---|
PENDING | No action. A charge attempt has started or the checkout is waiting for the buyer. |
PROCESSING | No action. The charge is in progress. |
PAID | Fulfil the order. chargedAmount is what the buyer paid. Keep succeededTransactionId: you need it to refund. |
FAILED | Read errorTransaction to see why. The checkout can be charged again until it expires or its allowed charge attempts are used up. |
EXPIRED | The checkout can no longer be paid. Create a new one if the buyer still wants to pay. |
UNKNOWN | The outcome could not be determined, and the checkout cannot be paid again. Contact Payment Labs support before you fulfil. |
New statuses may be added. If you see a value you do not recognise, fetch the checkout with Get Checkout.
Payload
data is the checkout as Get Checkout describes it, read when the webhook is sent. Fields with no value are omitted. Amounts use the Money object. payableAmount is never included in this payload. Call Get Checkout if you need it.
| Field | Type | Description |
|---|---|---|
id | string | Checkout ID, for example S-01JD3K5N7P9R1T3V5X7Z9B1D3F. |
status | string | Checkout status: PENDING, PROCESSING, PAID, FAILED, EXPIRED or UNKNOWN. See the table above. |
merchantId | string | Your merchant ID. |
merchantName | string | Your business name as the buyer sees it. |
buyerId | string | ID of the buyer. |
buyerEmail | string | Buyer's email address. |
alias | string | Short name for the checkout, shown to the buyer. |
description | string | Longer description of what the buyer is paying for. |
referenceId | string | Your own reference for the checkout, for example your order number. |
statementAlias | string | Text shown on the buyer's card statement after your account's statement prefix, as sent at creation. Omitted when not set. |
amount | Money | Amount the checkout asks for. |
chargedAmount | Money | Amount actually charged to the buyer. Set once the checkout is paid; read it, not amount, when you reconcile. It can be missing on some older paid checkouts, so use status to know whether a payment happened. |
isMerchantInitiated | boolean | true if you charged the checkout with Charge Checkout rather than the buyer paying. |
hasRefunds | boolean | true once a refund has been created for the checkout. |
succeededTransactionId | string | ID of the charge attempt that paid the checkout. Use it to create a refund. |
succeededCheckoutInstrumentId | string | ID of the card or account that paid the checkout. |
lastSucceededAt | string | When the checkout was paid, in ISO 8601 UTC. |
lastErroredAt | string | When the latest charge attempt failed, in ISO 8601 UTC. |
errorTransaction | object | Details of the latest failed charge attempt. Set when status is FAILED. See the table below. |
errorReason | string | Deprecated. Use errorTransaction.errorReason. |
expiresAt | string | When the checkout stops accepting payment, in ISO 8601 UTC. |
enabledCheckoutInstruments | string[] | Instrument types the buyer may pay with. Card types are payment-card-1, payment-card-2, payment-card-3; bank types are bank-transfer-2, bank-transfer-3; third-party wallet tokens are third-party-token-1, third-party-token-3; an in-person card on a terminal is payment-card-present-3. |
authenticationOptions | string | How the buyer must identify: GUEST_ONLY, AUTHENTICATED_ONLY (signed in), or ALL (either). |
links | object | checkout: a link you can send to the buyer. embeddable: a URL to load in an iframe. |
redirectLinks | object | Where the buyer is sent after paying: successRedirectUrl, failureRedirectUrl and expiredRedirectUrl. |
termsOfServiceUrl | string | Your terms of service, shown to the buyer. |
privacyPolicyUrl | string | Your privacy policy, shown to the buyer. |
auditInfo | object | createdAt, updatedAt (ISO 8601 UTC), createdBy and updatedBy. |
errorTransaction object:
| Field | Type | Description |
|---|---|---|
transactionId | string | ID of the failed charge attempt. |
checkoutInstrumentId | string | ID of the card or account that was charged. |
instrumentType | string | Type of that instrument, from the list in enabledCheckoutInstruments. |
errorReason | string | Broad cause. MISSING_INSTRUMENT: no instrument was given; the buyer must add one. INVALID_INSTRUMENT: the instrument is not valid; the buyer must check it. CHARGE_INSTRUMENT_ERROR: the charge was declined; the buyer should try another instrument. APPLICATION_ERROR: the checkout could not be processed. |
extendedErrorReason | string | Precise decline reason, when the card network gives one: INSUFFICIENT_FUNDS, EXPIRED_CARD, INVALID_CVV, DO_NOT_HONOR, TRANSACTION_NOT_PERMITTED, RESTRICTED_CARD, DUPLICATE_TRANSACTION, INVALID_ACCOUNT_NUMBER, INVALID_AMOUNT, INVALID_CURRENCY, CALL_ISSUER, ADDRESS_VERIFICATION_FAILED, MERCHANT_RULE_VALIDATION, THREE_D_SECURE_REQUIRED, THREE_D_SECURE_FAILED, THREE_D_SECURE_EXPIRED, NEW_ACCOUNT_INFO_AVAILABLE, PAYMENT_CANCELLED_BY_CARDHOLDER, RETRY_LATER, PROCESSOR_UNAVAILABLE, UNKNOWN_ERROR. |
Example
The full request body Payment Labs sends:
{
"payorId": "C-01JBX2Q8F4H6K8M0N2P4R6T8VW",
"event": "checkout-status-changed",
"timestamp": "2026-04-02T18:31:09.442Z",
"data": {
"id": "S-01JD3K5N7P9R1T3V5X7Z9B1D3F",
"buyerEmail": "[email protected]",
"alias": "Order 5521",
"description": "Annual membership",
"referenceId": "order-5521",
"statementAlias": "ORDER 5521",
"amount": {
"value": 89.99,
"wholeValue": 8999,
"currency": "USD",
"formattedValue": "$89.99",
"digits": 2
},
"chargedAmount": {
"value": 89.99,
"wholeValue": 8999,
"currency": "USD",
"formattedValue": "$89.99",
"digits": 2
},
"status": "PAID",
"succeededTransactionId": "ST-01JD3K8Q2S4U6W8Y0A2C4E6G8J",
"succeededCheckoutInstrumentId": "SI-01JD3K7M9P1R3T5V7X9Z1B3D5F",
"expiresAt": "2026-04-09T18:00:00.000Z",
"auditInfo": {
"createdAt": "2026-04-02T18:00:00.000Z",
"updatedAt": "2026-04-02T18:31:08.910Z",
"createdBy": "[email protected]",
"updatedBy": "[email protected]"
},
"lastSucceededAt": "2026-04-02T18:31:08.000Z",
"termsOfServiceUrl": "https://shop.example.com/terms",
"privacyPolicyUrl": "https://shop.example.com/privacy",
"enabledCheckoutInstruments": ["payment-card-3", "bank-transfer-3"],
"buyerId": "U-01JBX5K7M9P1Q3R5S7T9V1W3X5",
"merchantId": "C-01JBX2Q8F4H6K8M0N2P4R6T8VW",
"merchantName": "Example Fitness Club",
"redirectLinks": {
"successRedirectUrl": "https://shop.example.com/orders/5521/thanks"
},
"links": {
"embeddable": "https://checkout.example.com/embed/S-01JD3K5N7P9R1T3V5X7Z9B1D3F",
"checkout": "https://checkout.example.com/S-01JD3K5N7P9R1T3V5X7Z9B1D3F"
},
"authenticationOptions": "ALL",
"hasRefunds": false,
"isMerchantInitiated": false
}
}