Skip to content

Refunds

A refund returns money to a customer from a payment that succeeded, in full or in part. It is its own object with its own lifecycle: the payment intent stays succeeded, and fees are not returned by a refund. A payment can be refunded more than once, until all of it has been.

MethodWhat can be refunded
cardAll of the payment, or part of it. Part of a card payment cannot be refunded on the day it was made: refund all of it the same day, or part of it from the next day.
cashThe whole payment only: amount must be the whole amount, or left out. The refund is assisted: see Accepting cash.
qrphNot refundable through the API. The request is refused, with refund_not_supported_by_provider when the payment's provider can't refund it and refund_not_possible otherwise, and nothing is recorded: refund the customer another way, such as in cash, and keep a record of it.

A payment intent that has not succeeded, or that can no longer be refunded, is refused with refund_not_possible.

Name the payment intent. Leave amount out to refund what remains, or give an amount in the currency's minor unit for a partial refund. reason is optional: requested_by_customer, duplicate or fraudulent. The Idempotency-Key header is required, so a request that timed out can be sent again without refunding twice (see Idempotency).

Terminal window
curl https://api.example.com/v1/refunds \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Idempotency-Key: order-1042-refund-1" \
-H "Content-Type: application/json" \
-d '{
"payment_intent": "pi_01j9x2m8k4q7r5t3v6w8y0z2a4",
"amount": 2500,
"reason": "requested_by_customer"
}'

The answer is 201 with the refund:

{
"id": "re_01j9x3a1b2c3d4e5f6g7h8j9k0",
"object": "refund",
"amount": 2500,
"currency": "php",
"payment_intent": "pi_01j9x2m8k4q7r5t3v6w8y0z2a4",
"status": "succeeded",
"reason": "requested_by_customer",
"failure_reason": null,
"metadata": {},
"livemode": false,
"created": 1790411400
}

The calls are Create a refund, Retrieve a refund and List refunds, which takes payment_intent to list one payment's refunds.

statusWhen
createdThe moment it is made.
processingIt is on its way. A refund.succeeded or refund.failed event follows.
awaiting_approvalHeld for review: see below.
succeededIt reached the customer. Final.
failedIt could not be made. failure_reason says why. Final.

Every refund made sends refund.created, then refund.updated as it goes on its way, then refund.succeeded or refund.failed. Go by the refund's status, not by the order events arrive in (see Webhooks).

The platform's risk checks look at a refund before it is sent. Most pass at once. One they want to look at is held as awaiting_approval: nothing is refunded while it waits, and the amount stays held against what the payment has left to refund. Once the platform's risk team has decided, it goes on (processing, then succeeded or failed), or it fails as risk_declined. Poll the refund or wait for refund.updated and refund.failed.

Each is an error in the usual envelope, and in each nothing is refunded. amount_exceeds_refundable, refund_in_progress, refund_not_possible (for a payment that cannot be refunded at all) and refund_not_supported_by_provider are refused before any refund is made. The others are refused once the card provider or the risk checks have answered: the refund is kept, failed with the same failure_reason, and is listed and sent as refund.failed like any other. That includes refund_not_possible when the card provider says so.

typecodeWhen
invariant_violationamount_exceeds_refundableMore than the payment has left to refund.
timeout_or_in_progressrefund_in_progressAnother refund of the same payment is still being processed. Some card payments are refunded one refund at a time; see below.
policy_rejectionrefund_not_possibleThe payment intent has not succeeded, was not paid by card or cash, or can no longer be refunded.
policy_rejectionrefund_not_supported_by_providerThe payment was made by QR, and its provider can't refund it.
policy_rejectionrefund_not_yet_availablePart of a card payment cannot be refunded on the day it was made.
policy_rejectionrefunds_not_enabledRefunds are not enabled for your account with its card provider. Ask your platform operator to have them enabled.
policy_rejectionrisk_declinedThe platform's risk checks declined the refund. Nothing was refunded; ask your platform operator.
policy_rejectionrestrictedRefunds are restricted on your account. Nothing was refunded; ask your platform operator.
validation_failureinvalid_parameterA parameter is missing or not valid, such as a part of a cash payment (param is amount).

Some card payments are refunded one refund at a time: while one refund of the payment is processing, another is refused with 409, type timeout_or_in_progress and code refund_in_progress. Nothing is recorded for it, and your Idempotency-Key is not used up. Wait for the first refund's refund.succeeded or refund.failed, then send the same request again, with the same key.

A refund is usually settled within moments. Rarely, one stays processing while the platform's payments team confirms with the card provider whether it was made; it then succeeds or fails as any refund does, and the payment can be refunded again.

failure_reason on a failed refund is one of declined, refund_not_possible, refund_not_yet_available, refunds_not_enabled, restricted, risk_declined or unknown.