Skip to main content

The operator picks the source

When an invoice was paid with a single payment method, a refund routes back to that method automatically. When an invoice was paid with multiple payment sources (for example 100onacardplus100 on a card plus 100 by check), Arcus does not guess which source to refund. The operator decides how to split the refund across the original sources. This matches the industry standard. Stripe’s partial-refund guidance and NetSuite’s customer-return refund flow both have the merchant explicitly choose which charge or payment a refund draws from. There is no automatic proportional routing.

Who can issue a refund

POST /v1/returns/{id}/refund needs both the returns:write and payments:write scopes on the API key, and the identity behind the key must also hold the permission to refund or void payments (payments.refund_void). Refunds are the highest-trust action in the books, so a call that lacks any of the three is refused with 403. A return can be refunded once it is received, inspecting, restocked, written off, sent to the vendor, or closed. A refund-only return can also be refunded while it is still authorized. A return in any other status returns 409 with code: state_transition_invalid.

Multi-source refund allocations

To split a refund across payment sources, supply an allocations array on the refund request. Each allocation names an order_payments.id from the invoice’s original order and the dollar amount to refund against it.

Rules

  • Every payment_id must belong to the same order as the RMA’s original invoice.
  • SUM(allocations[].amount) must equal the total refund (amount) within one cent.
  • Each allocation must not exceed that source’s remaining refundable amount (payment.amount - payment.refund_amount).
  • All allocations are processed inside a single transaction. If any allocation fails, the entire refund is rolled back. Nothing partial is ever recorded.

What you get back

A multi-source refund returns payment_method_type: "multi_source", a single GL batch_id that groups every per-allocation journal entry, and an allocations[] array with the per-source result rows. The response also carries the return_number, and a status of succeeded, or already_processed when the same refund was issued before.

Repeating a refund

Calling the refund again for the same return with the same amount returns the result of the first refund instead of refunding twice (status: "already_processed"). A different amount for a return that was already refunded returns 409 with code: refund_already_issued. Send an Idempotency-Key header as well, so a retry after a network failure replays the original response.

When a refund is on hold

Accounting can put a return’s refund on hold with a question for the office. While the hold is in place, every refund door refuses the return, including this one: the call returns 409 with code: refund_on_hold, nothing is refunded, and no amount owed changes. The hold does not move money; it is a stop sign until the office answers. The error body names the hold in meta.refund_hold:
Do not retry a held refund in a loop. The hold clears when the office answers the question in Arcus (Answer and release on the RMAs Ready for Refund list in Finance > Receivables > AR Management); after that, call the refund again. Two other 409 answers explain a refund that cannot go through now: already_settled, when what is owed on the return is already settled so refunding more would pay the customer twice, and state_transition_invalid, described above.

Card processing fees are not refunded

When a refund allocation draws from a card source, the customer receives the allocated amount, but the original card-processing fee charged at sale time is not recovered. This is the standard behavior for card networks and Stripe: the processing fee on the original charge is non-refundable. Arcus surfaces a non-returnable-processing-fee disclaimer in the refund UI whenever a card source is part of the split.

Single-source refunds

If you do not supply allocations, the refund routes to a single source using the payment_method field (original, store_credit, check, or cash). This is the simplest path for invoices paid by one method.