Undo an offline refund
Reverses a refund record out of every total it touched, leaving the refund itself DECLINED and the payment refundable again. It is meant for an offline refund (manual true, gateway_status MANUAL) — a record of a refund made by some other means, where no money ever left through a gateway, so the record can simply be withdrawn. Nothing is sent to the gateway, in either direction: this changes Shuttle’s books only. The refund rules themselves, including what may be refunded and how an offline refund is recorded, belong to Refund a payment.
Where you can do this
Section titled “Where you can do this”- Merchant View: Transaction (Undo Refund)
Before you start
Section titled “Before you start”- The object is a refund (a
ref_id; the same refund read as a transaction carries atr_id, and Merchant View swaps the prefix before calling). - Its status is SUCCESS, PENDING, DECLINED, UNRESOLVED or REQAUTH, or its
gateway_statusis MANUAL, which is accepted whatever the status. A refund left in ROLLBACK or UNATTRIBUTED cannot be undone. - The payment or capture the refund was taken from, and the refund’s contract, still exist.
- No other payment, refund or capture is being processed on that contract at the same moment.
- Merchant View only offers the control on an offline refund that is not already DECLINED; the server is broader (see Rules).
Checked by the API means Shuttle refuses the request however it is sent; a screen name means only that screen refuses it, and a direct API call would be accepted.
| Rule | Checked by | What you see |
|---|---|---|
refund_id must resolve to a transaction: the ref_ prefix is stripped and the object fetched directly; anything else is searched as an alt_key among payment transactions, newest first |
The API | NOT_FOUND: “Transaction not found” (404) |
The object must be a refund (action REFUND) |
The API | VALIDATION_ERROR: “Not a refund” (400) |
| Shuttle re-checks that the id names an existing transaction and that it is a refund | The API | INVALID (BOLT-7048) |
The refund’s status must be SUCCESS, PENDING, DECLINED, UNRESOLVED or REQAUTH, or its gateway_status must be MANUAL; a refund in ROLLBACK or UNATTRIBUTED is refused |
The API | INVALID (BOLT-7048) |
| The contract must not be busy: the reversal takes the contract’s processing lock, waiting up to 30 seconds for it | The API | INVALID (BOLT-7059) with Shuttle’s lock message |
What happens
Section titled “What happens”- The refund becomes DECLINED. Its
amountandreasonare left as recorded,processedis filled in if it was empty, and the caller receives the refund object back with HTTP 200 as{ refund }, honouringexpand. - Everything the refund took away is put back: the payment’s
balancerises and itsrefundedfalls by the refund amount, and the charge, instalment and contract completed and refunded totals follow. A refund of a capture also restores the authorisation the capture came from. A payment taken in a terminal batch has its batch item amount restored. - The payment is refundable again for the amount put back, through Refund a payment as usual.
- No money moves and nothing is sent to the gateway. For an offline refund, which was only ever a record, that is the whole story; a gateway refund that really settled is not pulled back, only the books change.
- Webhooks: REFUND.FAILED for the refund, PAYMENT.UPDATE for the payment it was taken from (CAPTURE.UPDATE plus the authorisation’s PAYMENT.UPDATE when the refund was against a capture), and CONTRACT.UPDATE unless the contract is a one-off due at once. No email or SMS is sent to the payer.
- The contract’s last transaction becomes this declined refund, so the contract’s latest activity reads as a declined refund from then on.
Who can do this
Section titled “Who can do this”- Roles: Admin and Support.
- Permission keys (for clients managing permissions directly): any one of
agreement,payment_contract,payment_transactionor*, held on the client or on the refund’s division; Admin’s*satisfies it. Without one the caller sees UNAUTHORIZED: “Unauthorized” (401). A session tied to an account is accepted for that account’s own refunds without holding any of these keys; a session tied to a different account is refused with NO_PERMISSION: “No permissions” (403). Merchant View shows the control to any user holdingpayment_transaction(or*) on any object, so a user whose key is on neither the client nor the refund’s division sees the control and is refused by the server, while a user holding onlyagreementorpayment_contracton the division is accepted by the server but never sees the control. - App options: none. Unlike Refund, the Undo Refund control is not behind the instance’s
refundoption; it appears whenever the refund qualifies and the user holds the key. - API keys: an instance session reaches the route with the same check. The route is not part of the public API spec (see Rules).
Related
Section titled “Related”Was this page helpful?
What went wrong?
Thanks for telling us.