succeeded: a re_test_… /
re_live_… object your server creates with a secret key. It runs through the same engine as a
refund made in the dashboard, so it shows up there, on the receipt, and on the payment’s
amount_refunded.
1
Refund the payment
Response
payment is a pay_… of yours whose status is succeeded. A bank debit still processing is
400 payment_not_refundable until it settles. A card refund sent before the processor has settled
the charge can be refused: the create answers 402 refund_failed (in sandbox, a refund right after
the capture came back with failure_code: card_declined), and that refund stays failed. Refund
again later, with a new Idempotency-Key. amount is optional, in the
smallest unit of the currency, so 2500 is $25.00; leave it out to refund everything that has not
been refunded yet. currency is the payment’s. reason is optional, up to 200 characters, and
is shown on the refund in the dashboard and on the receipt.2
Read it back
402, and this is where you
see why.Idempotency-Key is required, as on POST /payments. For 24 hours, the same key
with the same body answers the same refund, byte for byte, with Idempotent-Replayed: true; the same
key with any other body (a different payment, amount or reason) is 400 idempotency_key_reused,
and so is a value you already used on another endpoint, such as the charge you are now refunding.
After that the refund itself still holds the key: sent again by the same API key with the same
payment and amount, it answers that refund as it is now, and with another payment or amount
it is 400 idempotency_key_reused. Use one fresh key per refund attempt.
Refunds made in the dashboard on a payment made through this API are re_… objects too: they
retrieve, list and emit refund.succeeded like any other.
Status
status is Payra’s own lifecycle. It is never a string from the processor.
Why a refund failed
failure is set when status is failed, and null otherwise. It carries a code from the same
fixed vocabulary as a payment failure and a message written by
Payra; the processor’s own wording is never relayed.
Refusals
A refusal is an answer, not an outage: the create responds402 refund_failed and leaves the
refund behind for you to read.
code is refund_failed for every refusal, so failure_code is what you branch on; it is the
refund’s failure.code, from the vocabulary above.
When Payra cannot tell whether the processor received the refund (the request timed out, or the
connection failed), the create answers 201 with status: "pending" instead, and a later webhook says
how it ended.
The remaining balance
Each payment carriesamount_refunded: how much of its amount has gone back so far, counting
refunds that succeeded wherever they were made, the API or the dashboard. A refund’s amount
may not exceed amount − amount_refunded (400 refund_amount_exceeds_balance; the message says
how much is left). Partial refunds can be repeated until the payment is fully refunded.
A pending refund does not reduce the balance yet, but it blocks another refund of the same
payment until it succeeds or fails: one at a time, 409 refund_in_flight for the second. Send it
again with a new Idempotency-Key once the first has ended; the same key replays the 409.
The payment’s own status stays succeeded after a refund. To know whether money went back, read
amount_refunded, list the payment’s refunds, or listen to refund.succeeded.
Receipts
The customer is emailed a refund receipt once the refund issucceeded, when the payment belongs to
a customer with an email address whose email notifications are on, and the workspace’s notifications
are not paused. A payment with no customer gets none.
reason is shown on the receipt and in the dashboard. When you omit it, they read “Refund
requested via API” while the refund object answers reason: null.
Listing refunds
GET /refunds answers the refunds of payments made through this API, including those made in the
dashboard, newest first, a page at a time. It
takes limit and starting_after, and works the same as every other list; see
pagination for walking the pages. payment=pay_… narrows it to one payment’s
refunds; an unknown payment answers an empty list.
Response (abbreviated)