Refund a Payment
Requires the payments:refund scope, which is separate from payments:capture — an application needs to be granted refund access explicitly.
Refund everything
curl -X POST https://dev.gladys.the-all.io/api/v1/payments/pay_abc123/refunds \
-H "Authorization: Bearer <your access token>" \
-H "Idempotency-Key: <a unique key for this request>" \
-H "Content-Type: application/json" \
-d '{"reason": "Customer requested a refund"}'
Omitting amount refunds everything not already refunded — you don't need to compute a remainder yourself.
Refund part of it
curl -X POST https://dev.gladys.the-all.io/api/v1/payments/pay_abc123/refunds \
-H "Authorization: Bearer <your access token>" \
-H "Idempotency-Key: <a unique key for this request>" \
-H "Content-Type: application/json" \
-d '{"amount": 50000, "reason": "Partial return"}'
A payment can be refunded more than once — each partial refund is its own object with its own reference, so you can tell them apart later. List them with:
curl https://dev.gladys.the-all.io/api/v1/payments/pay_abc123/refunds \
-H "Authorization: Bearer <your access token>"
Rules to design around
- Only a
CAPTUREDpayment can be refunded. An authorized-but-not-yet-captured hold should be cancelled instead (see Accept a Payment). - You can't over-refund. Requesting more than what's still refundable (
amount - already refunded) fails with a 400 — it never partially applies. - The fee isn't reversed. The payer is credited the full refunded amount, but the original transaction fee stays with Gladys — a fully-refunded payment leaves you short exactly that fee. Account for this in your reconciliation rather than assuming a full refund zeroes out.
- A refund fires its own webhook.
payment.refundedincludes arefundobject naming which refund it was — see Receive Webhooks.
Always send an Idempotency-Key on refund calls — retrying an unacknowledged refund request without one risks issuing it twice.