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 isPAID. 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" }'| Field | Required | Notes |
|---|---|---|
amount | Yes | A 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). |
reason | Yes | At 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
PENDINGorPROCESSING, a new one on the same checkout with Refund Checkout Transaction returns409. Wait forCOMPLETEDorFAILEDfirst.
Step 3: Follow the refund
Refunds are processed asynchronously:
| Status | Meaning |
|---|---|
PENDING | Created and waiting to be processed. |
PROCESSING | Being processed. |
COMPLETED | The refund was accepted. The buyer's bank posts it on its own schedule. |
FAILED | The 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:
- Call List Subscription Payments and take the
checkoutIdof the cycle to refund. - Call Get Checkout with that ID and take
succeededTransactionId. - 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 thesubscriptionIdandsubscriptionPaymentId. - 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
hasRefundsbecomestrue. 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
| Response | Cause | What to do |
|---|---|---|
400 VALIDATION_ERROR, details.amount[].code = INVALID_TRANSACTION_STATUS | The transaction is not SUCCEEDED. | Refund the checkout's succeededTransactionId. |
400 VALIDATION_ERROR, CANNOT_PARTIALLY_REFUND | Only a full refund is accepted for this transaction. | Send the full charged amount. |
400 VALIDATION_ERROR, CANNOT_REFUND_MORE_THAN_ORIGINAL_AMOUNT | This refund plus earlier ones exceeds the charge. constraints shows the remaining amount. | Lower the amount. |
400 VALIDATION_ERROR, REFUND_NOT_SUPPORTED | This transaction cannot be refunded through the API. | Contact Payment Labs support. |
404 NOT_FOUND | The checkout, transaction, subscription or subscription payment does not exist, or the transaction belongs to another checkout. | Check the IDs. |
409 VALIDATION_ERROR | A 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. |
403 | Your credential lacks the Merchant Approver permission. | Use a credential with the right role. |
Next steps
- Settlements and Reconciliation to match refunds with your payouts.
- Checkout Statuses and Failure Reasons
Updated about 24 hours ago
