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

Before you start

  • The object is a refund (a ref_ id; the same refund read as a transaction carries a tr_ id, and Merchant View swaps the prefix before calling).
  • Its status is SUCCESS, PENDING, DECLINED, UNRESOLVED or REQAUTH, or its gateway_status is 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.

RuleChecked byWhat 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 firstThe APINOT_FOUND: "Transaction not found" (404)
The object must be a refund (action REFUND)The APIVALIDATION_ERROR: "Not a refund" (400)
Shuttle re-checks that the id names an existing transaction and that it is a refundThe APIINVALID (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 refusedThe APIINVALID (BOLT-7048)
The contract must not be busy: the reversal takes the contract's processing lock, waiting up to 30 seconds for itThe APIINVALID (BOLT-7059) with Shuttle's lock message

What happens

  • The refund becomes DECLINED. Its amount and reason are left as recorded, processed is filled in if it was empty, and the caller receives the refund object back with HTTP 200 as { refund }, honouring expand.
  • Everything the refund took away is put back: the payment's balance rises and its refunded falls 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_transaction or *, 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 holding payment_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 only agreement or payment_contract on 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 refund option; 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


Did this page help you?