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
- Merchant View: Transaction (Undo Refund)
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).
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
- 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
- Roles: Admin only. Support holds none of the keys below; reversing a refund moves money between the recorded totals and is deliberately withheld from 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
Updated about 6 hours ago
Did this page help you?