A valid request URL is required to generate request examples{
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"environment": "live",
"refund_ref": "<string>",
"charge_ref": "<string>",
"currency": "BRL",
"amount_minor": 123,
"refunded_minor": 123,
"remaining_minor": 123
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Refund an invoice
Requires billing:write. Hands money back on the payment behind one paid invoice — all of it, or part.
This is the one act in the API that performing twice cannot be undone. Send an Idempotency-Key and send the same one when you retry.
The amount is optional, and omitting it is the safe spelling
With no amount_minor, everything still refundable goes back — the gateway subtracts what has already gone, including refunds issued in its own dashboard. An explicit amount larger than what remains is refused with 422 and the remainder named, rather than passed down to come back as a sentence about a charge id.
What remains is re-read from the gateway inside this call, never taken from what a screen was showing. The window between rendering a page and clicking a button is exactly where a second refund lands.
What the invoice does afterwards
Nothing. A refunded invoice stays paid and keeps its total, at the gateway and therefore here: the payment is what changed, not the bill. What the money did is a fact of its own — invoice.refunded, carrying the gateway’s cumulative refunded figure — published when the gateway’s own webhook is applied, which is also what reverses a referral commission.
This call publishes invoice.refund_requested instead, with the actor: it is past tense about a request somebody with billing:write made, and it is a staff audit record rather than an outcome to build automation on.
A valid request URL is required to generate request examples{
"invoice_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"environment": "live",
"refund_ref": "<string>",
"charge_ref": "<string>",
"currency": "BRL",
"amount_minor": 123,
"refunded_minor": 123,
"remaining_minor": 123
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}{
"error": {
"code": "forbidden",
"message": "your role does not allow this action"
}
}Authorizations
A staff session token, uk_st_…. Minted by sign-up, sign-in or the two-factor exchange. Only a 401 means it is spent; not_a_member (403) is about the organization named in X-Organization-Id and leaves the token good for the others.
Headers
The organization the caller is acting on — the org_… code that appears in the panel URL. It identifies; the membership JOIN is what authorizes, so a forged code reads nothing: the answer is not_a_member (403), which does not mean the session is over. Absent, the session's default organization answers, or — if that membership was revoked while the session was open — any other one the caller still holds.
Forwarded to the payment gateway as its idempotency key, so a retry of this call does not charge twice or move a subscription twice.
This is not the guarantee Idempotency-Key carries on the API-key surface: nothing is stored here and a replay is not answered with the original response. It is passed through, and what it buys is whatever the gateway does with it — for Stripe, the original result is replayed for 24 hours.
Send a fresh key per act you mean to perform, and the same key with the same body when you are retrying one. The gateway compares the parameters, so a key reused for a different act is refused there rather than replayed.
255Path Parameters
The invoice's id in this system — not the gateway's reference.
Query Parameters
Which environment to act in. A view parameter, valid only on the staff surface — a machine credential never chooses its environment, it is resolved from the key.
live, test Body
Why, in your own words. Required: the line outlives the conversation that produced it, and a refund nobody can explain is one nobody dares repeat or account for. Recorded at the gateway as metadata, never mapped onto its own reason vocabulary — those carry consequences (Stripe's fraudulent marks the payment in its dispute tooling) that a support note must not trigger by wording.
How much to hand back, in the payment's minor units. Omit it — or send 0 — for everything that remains, which is the commonest act and the one nobody should have to type a number for.
x >= 0Response
The refund, as the gateway made it.
One refund, as the gateway made it.
live, test The gateway's id for the refund itself.
The payment the money came out of.
"BRL"
What this refund handed back. Stated by the gateway rather than echoed from the request, which is the difference that matters when the amount was omitted.
What the payment has handed back in total, re-read after the act. 0 when that re-read did not get through — the refund still happened, and see remaining_minor.
What is still refundable afterwards, or null when the gateway could not be re-read. Null rather than a computed guess on purpose: a screen rendering "nothing left" over a payment nobody re-read is the reassurance that stops the next person checking.