Flow: refund
A refund is a separate operation on top of an already paid invoice. No separate “refund invoice” is created: the original one changes its status, and the result arrives in a callback.
- Wait for the payment. A refund is accepted only with
payment_status: PAID. Refunding an unpaid invoice returns422 INVOICE_NOT_PAIDimmediately; nothing changes, and retrying is pointless. - Request the refund:
POST /invoices/{invoice_id}/refundwith an empty body{}. The response is202withinvoice_idandrefund_status: processing. - Wait for the
refund.callback (updated refund.in the legacy envelope): the refund status arrives incompleted data.. Deduplicate it by the event identifier like any other event (see “Callbacks”).invoice. refund_status - Reconcile against the invoice: after a refund
GET /invoices/{invoice_id}returnsstatus: Refundwithpayment_status: PAID. The paid flag is not reset — the money was charged, and that fact stays in the history.
In the XML flow the refund arrives as the same SendPaymentTransaction. It has no separate name: a refund notification is recognized by the refund status in InvoiceInfo/InvoiceStatus and the absence of the PaymentTransactionInfo block; the sandbox refunds instantly and always successfully, so it sends the single status Refund. Details in “Callbacks”.
Request and response
// POST /api/v3/projects/1001/invoices/{invoice_id}/refund
{}
// 202 Accepted
{
"success": true,
"data": {
"invoice_id": "4c702dc3-176e-4365-ab4d-8fd22cbcfab1",
"refund_status": "processing"
}
}The invoice after a refund
// GET /api/v3/projects/1001/invoices/{invoice_id}
{
"status": "Refund",
"payment_status": "PAID"
}Refunding an unpaid invoice
// 422 Unprocessable Entity
{
"success": false,
"error": { "code": "INVOICE_NOT_PAID" }
}