Refunds

Return money to a buyer from a paid checkout or a subscription billing cycle, and follow the refund until it completes.

A refund returns all or part of a successful charge to the buyer's card or bank account. This page shows how to create one, how to follow it, and which rules the API enforces.

Before you start

  • Get a token with Create Access Token, the same login payors use, from a credential with the Merchant Approver permission. Reading refunds needs only Merchant Read. See Permissions.
  • You can refund only a checkout transaction with status SUCCEEDED, which means a checkout that is PAID. There is no void or cancel: once a checkout is paid, a refund is the only way to return the money.

Step 1: Find the transaction to refund

Read the checkout with Get Checkout. For a PAID checkout, succeededTransactionId is the transaction to refund. List Checkout Transactions returns every attempt if you need them.

Step 2: Create the refund

Call Refund Checkout Transaction:

curl -X POST https://api-sandbox.paymentlabs.io/checkouts/S-01JBX7Z3K9M2N4P6Q8R0S2T4V6/transactions/ST-01JBX8C4D6F8G0H2J4K6M8N0P2/refunds \
  -H "Authorization: Bearer $PAYMENT_LABS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 49.99, "reason": "Order cancelled by the customer" }'
FieldRequiredNotes
amountYesA JSON number in the transaction's currency, at least 0.01. Send the full charged amount unless partial refunds work for your account (see below).
reasonYesAt least 3 characters. It is stored with the refund and returned when you read it.

The response is the refund, with status PENDING:

{
  "id": "RF-01JBXA2M4P6R8T0V2X4Z6B8D0F",
  "type": "CHECKOUT",
  "status": "PENDING",
  "amount": { "value": 49.99, "currency": "USD", "formattedValue": "$49.99", "digits": 2, "wholeValue": 4999 },
  "reason": "Order cancelled by the customer",
  "checkoutId": "S-01JBX7Z3K9M2N4P6Q8R0S2T4V6",
  "checkoutAlias": "Order 10482",
  "originalTransactionId": "ST-01JBX8C4D6F8G0H2J4K6M8N0P2",
  "merchantId": "C-01JBX2Q8F4H6K8M0N2P4R6T8VW",
  "buyerEmail": "[email protected]"
}

The checkout's hasRefunds becomes true.

Full and partial refunds

  • Some transactions can only be refunded in full. For those, any amount other than the full charge returns CANNOT_PARTIALLY_REFUND. Send the full amount in that case.
  • When partial refunds are possible, you can create several refunds on one transaction until their total reaches the charged amount. A refund that would go over it returns CANNOT_REFUND_MORE_THAN_ORIGINAL_AMOUNT.
  • Create one refund at a time. While a refund on a checkout is PENDING or PROCESSING, a new one on the same checkout with Refund Checkout Transaction returns 409. Wait for COMPLETED or FAILED first.

Step 3: Follow the refund

Refunds are processed asynchronously:

StatusMeaning
PENDINGCreated and waiting to be processed.
PROCESSINGBeing processed.
COMPLETEDThe refund was accepted. The buyer's bank posts it on its own schedule.
FAILEDThe refund did not go through. errorReason says why, for example REFUND_REJECTED when it was refused. You can create a new refund.

Register refund-status-changed to be told about each change, or read the refund with Get Refund. To list refunds, use List Checkout Refunds or Search Refunds.

Refund a subscription payment

Each billing cycle of a subscription is a subscription payment (RP-…) charged through its own checkout. Refund it through that checkout with Refund Checkout Transaction, the same operation as for any other checkout:

  1. Call List Subscription Payments and take the checkoutId of the cycle to refund.
  2. Call Get Checkout with that ID and take succeededTransactionId.
  3. Create the refund on that checkout and transaction:
curl -X POST https://api-sandbox.paymentlabs.io/checkouts/S-01JBXB9P1R3T5V7X9Z1B3D5F7H/transactions/ST-01JBXBA2S4V6W8Y0A2C4E6G8J0/refunds \
  -H "Authorization: Bearer $PAYMENT_LABS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 19.00, "reason": "Duplicate billing" }'
  • The body and the rules are the same as for any checkout refund. The refund has type: "SUBSCRIPTION" and carries the subscriptionId and subscriptionPaymentId.
  • Refunding a payment does not cancel the subscription. Cancel it separately if billing should stop.
  • List Subscription Payment Refunds returns the refunds of one cycle, and the payment's hasRefunds becomes true. Its path starts with /subscriptions (plural); the other subscription operations start with /subscription.

You can also refund a cycle directly with Refund Subscription Payment, which finds the cycle's charge for you:

curl -X POST https://api-sandbox.paymentlabs.io/subscriptions/R-01JBXB3N5Q7S9U1W3Y5A7C9E1G/payments/RP-01JBXB9P1R3T5V7X9Z1B3D5F7H/refunds \
  -H "Authorization: Bearer $PAYMENT_LABS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "amount": 19.00, "reason": "Duplicate billing" }'

The body and the amount rules are the same, and the refund is the same SUBSCRIPTION refund. One difference matters: this operation does not refuse a second refund while an earlier refund of the cycle is still PENDING or PROCESSING. Before each refund, call List Subscription Payment Refunds and wait until none is in progress, and after a timeout list the refunds before you retry. A 409 VALIDATION_ERROR from it means the cycle has no successful charge yet.

Errors and edge cases

ResponseCauseWhat to do
400 VALIDATION_ERROR, details.amount[].code = INVALID_TRANSACTION_STATUSThe transaction is not SUCCEEDED.Refund the checkout's succeededTransactionId.
400 VALIDATION_ERROR, CANNOT_PARTIALLY_REFUNDOnly a full refund is accepted for this transaction.Send the full charged amount.
400 VALIDATION_ERROR, CANNOT_REFUND_MORE_THAN_ORIGINAL_AMOUNTThis refund plus earlier ones exceeds the charge. constraints shows the remaining amount.Lower the amount.
400 VALIDATION_ERROR, REFUND_NOT_SUPPORTEDThis transaction cannot be refunded through the API.Contact Payment Labs support.
404 NOT_FOUNDThe checkout, transaction, subscription or subscription payment does not exist, or the transaction belongs to another checkout.Check the IDs.
409 VALIDATION_ERRORA refund on this checkout is still in progress, the amount rounds to zero in the currency, the total would exceed the charge, or this checkout cannot be refunded with this operation.Wait for the earlier refund to finish, or fix the amount.
403Your credential lacks the Merchant Approver permission.Use a credential with the right role.

Next steps


Did this page help you?