Refunds
A refund returns some or all of a completed payment to the customer. One
mutation, paymentRefund, refunds a payment whichever provider took it: it
reads the provider from the payment and issues the refund there, so you never
need to know how a payment was processed to reverse it.
Refunds need the refund permission, which every organization API key holds for its own organization and every agency API key holds for the organizations under its agency.
Issuing a refund
mutation {
paymentRefund(
input: {
payment: "PAYMENT_ID"
amount: "25.00"
reference: "order-1042-return"
idempotencyKey: "0b7f1c2e-6c3f-4a09-9b7f-2d3e9c1a5e10"
}
) {
id
payment
provider
amount
currency
status
processorReference
requestedAt
}
}paymentis the id of the payment to refund.amountis optional. Omit it to refund everything still refundable on the payment. An amount larger than what is left is refused.referenceis optional and is yours: use it to tie the refund to a return, a ticket, or an order in your own records.idempotencyKeyis optional but strongly recommended. See retrying safely.
What a successful response means
The status in the response depends on the provider, because providers refund
at different speeds.
| Provider | Status returned | What it means |
|---|---|---|
| NMI | COMPLETED |
The refund was approved on the spot. |
| CLP | RECEIVED |
The refund was accepted and will settle shortly. It becomes COMPLETED once the provider confirms it. |
| Plaid | — | Plaid payments cannot be refunded through the API yet. The call fails with a validation error. |
A refund the provider refuses is returned as an error rather than as a result
with a FAILED status, so a successful response always means the refund was
accepted. The error message carries the provider's response code, which you
can quote to support.
Retrying safely
A refund is money leaving your account, so a request that times out is the dangerous case: you do not know whether it went through, and repeating it could refund the customer twice.
Send an idempotencyKey with every refund. Any unique string works; a UUID is
a good choice. Repeating a call with the same key and the same organization is
answered exactly as the first call was: it returns the refund the first call
created, or repeats its rejection, and never issues a second refund. A repeat
that names a different payment or amount is refused with a conflict error, so a
key reused by mistake surfaces as a bug instead of a silent wrong answer.
If a call fails with a message saying the refund may or may not have been issued, do not retry with a new key. Repeat the call with the same key, and what happens depends on the provider. For a CLP payment the repeat either returns the refund that went through or resumes the one that did not, because CLP recognizes the original attempt. For an NMI payment the repeat tells you the outcome is still unknown rather than trying again, because NMI cannot make a second attempt safe. In either case, check the payment before doing anything else.
Partial refunds
Pass an amount smaller than the payment to refund part of it. A payment can
be refunded more than once until the refunded total reaches the amount
captured; each refund is checked against what is still refundable at the
moment it is issued.