APIRefund
Refund a payment
Issue a full or partial refund. Multiple partial refunds chain — each decrements remaining. Refunds are asynchronous at the acquirer: we return immediately, then deliver payment.refunded webhook(s) as the money clears (typically 1-5 business days).
POST
/v2/payments/{id}/refundsk_live_ / sk_test_
Idempotency is on you.
Use a unique
idempotency_key per refund attempt. Without it, two queue retries can issue two refunds. With it, the second call returns the cached result instantly (24h TTL).Path parameter
| Param | Description |
|---|---|
| {id} | Any of: cs_* session id, pay_* id, your order_id, or the connector reference. We resolve them all. |
Request body
| Field | Type | Description |
|---|---|---|
| amount | integer | Amount to refund in minor units. Omit for full refund of the remaining balance. Cannot exceed remaining (we 400 instead of overdrafting). |
| reason | string(500) | Free-form note. Stored in audit log, returned in payment.refunded webhook. |
| idempotency_key | string(128) | Replay-safe key. Strongly recommended for queue-driven systems. |
Response
| Field | Type | Description |
|---|---|---|
| status | string | refunded when fully refunded; partially_refunded while balance remains. |
| amount_refunded | integer | This call's refund amount. |
| total_refunded | integer | Sum across all refund calls on this payment. |
| remaining | integer | Still refundable balance. |
| connector_refund_id | string | Provider-side ref for support cases. |
Errors
| HTTP | Code | Reason |
|---|---|---|
| 400 | VALIDATION_ERROR | Negative or zero amount. |
| 400 | REFUND_EXCEEDS_BALANCE | Requested amount > remaining (already refunded shown in error). |
| 400 | INVALID_PAYMENT_STATE | Only succeeded or partially_refunded can be refunded. |
| 404 | NOT_FOUND | No payment matches {id} for your merchant. |
| 502 | CONNECTOR_REFUND_FAILED | Provider rejected the refund — check error_message. |
Webhook fired
On every successful refund call we enqueue payment.refunded to your webhook URL. Includes the refund object and updated total_refunded. Retried 8 times across 24h until you ACK with 2xx.