Refund a payment

Returns money to the payer for a successful payment or capture, in full or in part, either through the gateway that took the payment or as an offline record of a refund made by other means (manual true). A refund is its own transaction (a ref_ id) attached to the source; it reduces the source's balance and the completed totals of the charge, instalment and contract the source paid. Note the route: POST /c/api/payments/:id/refund, singular. An authorisation is not refunded; it is voided (Void an authorisation) or captured first (Capture an authorised payment).

Where you can do this

  • Merchant View: Refund a transaction (Refund)
  • Merchant View: Refund
  • API: Refund a payment (POST /payments/{payment_id}/refund) — amount, reason, manual true for an offline refund; :id is a payment, capture or transaction id, or the payment's alt_key
  • API: Refund a capture (POST /captures/{capture_id}/refund) — the same body against a capture id; same server rules, without Shuttle's lookup and count checks

Before you start

  • The source is a payment or a capture. Authorisations, voids and refunds cannot be refunded.
  • The source is in status SUCCESS, PENDING or UNATTRIBUTED and has a balance above zero (the part not yet refunded; for an UNATTRIBUTED payment, its full amount).
  • The source has been processed (has a processed date) unless it is UNATTRIBUTED, and its contract and the allocations that record which charges it paid still exist.
  • The gateway the source was taken on is active. An archived or inactive gateway blocks the refund even when it is offline.
  • For a gateway refund (manual absent or false): the gateway accepts a refund of this kind for the payment method type, a full refund when the amount equals the original amount, a partial refund otherwise. The gateway advertises this as the features FULL_REFUND, PARTIAL_REFUND and MULTI_REFUND under its payment_method_types.
  • From Merchant View: the instance option refund is on; refund_offline is on for the Offline choice to be offered.

Inputs

InputRequiredMeaning and constraints
amountnoDecimal as a string ("10.00"), above zero and no more than the source's balance. Omitted: the whole remaining balance. Any number of decimals is accepted server-side; Merchant View allows at most two and at least one minor unit.
reasonnoFree text. Omitted: recorded as "No reason given". The public spec marks it required; Merchant View limits it to 100 characters; the server does not limit its length.
manualnotrue records an offline refund: no gateway call, no money moves, no fee, gateway_status MANUAL. Default false.

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
:id on the payments route must resolve to a PAYMENT or CAPTURE transaction; a prefixed id is looked up directly, anything else is searched as the payment's alt_key (newest match wins)The APINOT_FOUND: "Payment not found"
An alt_key that matches two payments, the older created within the last six months, is ambiguousThe APIINVALID_REQUEST: "Duplicate alt_key"
The source must be SUCCESS, PENDING or UNATTRIBUTEDThe APIVALIDATION_ERROR (BOLT-9005)
amount must be above zero; zero, negative or a source with nothing left to refundThe APIINVALID_AMOUNT (BOLT-1168)
amount must not exceed the remaining balanceThe APIVALIDATION_ERROR (BOLT-9003)
A source already fully refunded is reported as such, with a distinct message when the earlier refund was offlineThe APIVALIDATION_ERROR (BOLT-1148: "already refunded" / "already refunded manually")
The source must have a processed date (unless UNATTRIBUTED), an existing contract, and intact charge allocationsThe APIINVALID_AMOUNT (BOLT-1168) when unprocessed; VALIDATION_ERROR (BOLT-1148) when the contract or an allocation is missing
The source's gateway must be active, also for an offline refundThe APIINVALID (BOLT-7185, archived or inactive gateway)
The source must have a payment connectorThe APIVALIDATION_ERROR (BOLT-9008)
A gateway refund needs the gateway to accept the refund type for the payment method type: TOTAL_AMOUNT when amount equals the source's original amount, PARTIAL_AMOUNT otherwise. The type is judged against the original amount, not the balance, so a second refund that clears the balance is sent as partial; a gateway that only accepts full refunds rejects itThe APIVALIDATION_ERROR (BOLT-9006)
A gateway that fails to answer leaves the refund UNRESOLVED and fails the callThe APIINVALID (BOLT-1147)
A gateway decline is not an error response: the call returns the refund with status DECLINED and the gateway's gateway_message; UNRESOLVED likewise. Only a request that produced no refund record failsThe APIHTTP 200 with refund.status DECLINED or UNRESOLVED
Any refund is allowed while the gateway's refund types allow it; the server has no notion of "one refund only". The gateway's MULTI_REFUND feature is advisory and is applied by Merchant View onlyThe APInone
Merchant View locks the whole amount to balance; a partial amount is editable only when the gateway advertises PARTIAL_REFUND, the whole-amount toggle only with FULL_REFUND; an offline refund allows bothMerchant View screeninputs disabled
Merchant View sends manual true when Offline is chosen, when the source is itself an offline (MANUAL) payment, or when the gateway lacks MULTI_REFUND and the amount differs from the balance; it forces Offline when the gateway advertises neither FULL_REFUND nor PARTIAL_REFUND; it warns that a partial refund on a gateway without MULTI_REFUND leaves the remainder unrefundable via the gatewayMerchant View screen"This will record the refund only..." warnings; confirmation modal
Merchant View rejects a partial amount below one minor unit, above balance, or with more than two decimals; the server accepts any scaleMerchant View screenRefund button disabled

What happens

  • The caller receives a refund object (ref_ id, amount, reason, reference, status, gateway_status, gateway_message, processed, source_transaction, payment) with status SUCCESS, PENDING, DECLINED or UNRESOLVED. A decline still returns HTTP 200; check status. Only a request that could not create a refund at all returns an error.
  • On SUCCESS or PENDING the source's balance falls and refunded rises by the amount; the charge, instalment and contract completed totals fall with it and the contract's last transaction becomes the refund. Refunding a capture also reduces the parent authorisation's balance. A payment taken in a terminal batch has its batch item amount reduced to what remains.
  • An offline refund (manual true) moves no money: it is recorded SUCCESS at once with gateway_status MANUAL and no fee, and can be reversed with Undo an offline refund. A gateway refund returns the money through the gateway, records the gateway's fee (from its response or its refund settings) and cannot be reversed here.
  • Webhooks: REFUND.SUCCESS, REFUND.PENDING, REFUND.FAILED or REFUND.UNRESOLVED for the refund; PAYMENT.UPDATE for the refunded payment (CAPTURE.UPDATE for a refunded capture, plus PAYMENT.UPDATE for its authorisation); CONTRACT.UPDATE on success or pending unless the contract is a one-off due at once or still being set up. No email or SMS is sent to the payer.
  • Later: a PENDING refund is completed when the gateway confirms it, at which point the totals move and REFUND.SUCCESS arrives. An UNATTRIBUTED source becomes SUCCESS as a side effect of being refunded.

Who can do this

  • Roles: Admin only.
  • Permission keys (for clients managing permissions directly): payment_transaction.refund on any one of the source's branding, channel, designation, initiative, legal entity, gateway or receipt template; Admin's * satisfies it. Whether a plain payment_transaction grant satisfies the sub-key is not traced. Without it the caller sees INVALID (HTTP 400) carrying Shuttle's permission message rather than NO_PERMISSION. Merchant View requires payment_transaction to open the screen and payment_transaction.refund on the source's initiative (or *) to show the form, otherwise "You do not have permissions to refund this transaction.".
  • Admin app options: refund shows the Refund control; refund_offline offers the Offline choice (Offline is forced regardless when the gateway advertises neither FULL_REFUND nor PARTIAL_REFUND).
  • API keys: an instance session reaches the route with the same server permission check; no additional option applies.

Related


Did this page help you?