Refunds¶
createRefund returns money from a payment that has already completed. For a pre-authorisation
that was never captured, cancel it instead. For a card payment that has not
settled yet, a merchant with voids enabled can void it instead, which avoids the
discount rate (%) (the transaction fee for the original sale still applies).
Note
Only payments with status COMPLETED can be refunded. A PENDING payment — which
every ACH payment is for a while — cannot be refunded until it completes. See
Payment status.
Headers¶
The standard three plus an idempotency key — createRefund will not
run without one, for the same reason createPayment will not: a blind retry would refund twice.
{
"x-aptean-apim": "<your api key>",
"x-aptean-tenant": "<your tenant id>",
"x-aptean-tenant-secret": "<your tenant secret>",
"idempotency-key": "<a unique value you generate>"
}
The mutation¶
mutation CreateRefund($input: CreateRefundInput!) {
createRefund(input: $input) {
code
message
error
refund {
id
amount
}
}
}
Full refund¶
Omit amount and the whole payment is refunded:
Partial refund¶
Supply amount in minor units:
{
"input": {
"paymentId": "<the payment id to refund>",
"refundReason": "One item returned",
"amount": 800
}
}
| Field | Type | Notes |
|---|---|---|
paymentId |
String | Required. |
refundReason |
String | Required. 1–65,535 characters. Stored on the refund and visible in the merchant portal. |
amount |
Int | Optional. Minor units. Minimum 100 — you cannot refund less than 1.00. Omit for a full refund. |
paymentRequestId |
ID | Optional. Refund against a specific payment request where a payment covered several. |
customData |
JSON | Optional key–value pairs. |
Warning
amount has a minimum of 100 (1.00 in the payment currency). A partial refund
of, say, 50 cents is rejected. If you need to return less than that, it cannot be done through
this API.
Warning
Omitting amount refunds everything. If you meant a partial refund and left the
field out because it was null in your code, you have just refunded the full payment. Make the
distinction explicit in your integration rather than relying on a nullable variable.
Multiple partial refunds¶
You can refund a payment more than once, as long as the running total never exceeds the original amount. Aptean Pay tracks what has already been refunded and rejects anything that would take it over.
The response¶
{
"data": {
"createRefund": {
"code": "SUCCESS",
"message": "Refund created.",
"error": null,
"refund": {
"id": "a2808c74-dae8-403f-ab7f-919fac8ae61b",
"amount": 12000
}
}
}
}
Store refund.id.
Note
As with payments, SUCCESS means accepted, not settled. A card refund typically
reaches the payer's statement in a few business days — that timing belongs to their issuer, not
to Aptean.
Common failures¶
These are the messages Aptean Pay actually returns:
| Message | Cause |
|---|---|
Unable to create refund, payment has not completed. Current payment status is … |
Only COMPLETED payments can be refunded. |
Unable to create refund, full amount has already been refunded. |
Nothing left to refund. |
Unable to create refund, partial refund amount will exceed payment amount. |
amount plus previous refunds is more than the payment. |
Unable to create refund, a partial refund must have the amount specified. |
A partial refund was implied but amount was missing. |
Unable to create refund, payment not found. |
Wrong paymentId, or the wrong environment. |
Unable to create refund, refund already exists for given id. |
The idempotency key was already used. |
Unable to create refund, full amount of specified payment request has already been refunded. |
That payment request is fully refunded already. |
idempotency key is required |
No idempotency-key header. |
Field "refundReason" of required type "String!" was not provided. |
refundReason is mandatory. |