Skip to content

Create a refund

POST
/v1/refunds
curl --request POST \
--url https://api.example.com/v1/refunds \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: order-1042-attempt-1' \
--data '{ "payment_intent": "pi_01j9x2m8k4q7r5t3v6w8y0z2a4", "amount": 1, "reason": "requested_by_customer", "metadata": { "order_id": "1042" } }'

Returns all or part of a succeeded card payment, or the whole of a succeeded cash payment (see Accepting cash: that refund stays processing until your operator records it paid out). Leave amount out to refund what remains. The payment intent stays succeeded; the refund is its own object. A payment can be refunded more than once, until all of it has been. Fees are not returned by a refund. In test mode, a card payment that was simulated paid is refunded at once: the refund comes back succeeded and nothing is returned.

The refund comes back succeeded, processing while it is still on its way (a refund.succeeded or refund.failed event follows), or failed with a failure_reason. Every refund made sends refund.created, then refund.updated as it goes on its way, then refund.succeeded or refund.failed.

Refusals, each with nothing refunded. The first three are refused before any refund is made. The last two, and refund_not_possible when the card provider says so, are refused once the card provider has answered: the refund is kept, failed with the same failure_reason, and is listed and sent as refund.failed like any other.

type code When
invariant_violation amount_exceeds_refundable More than the payment has left to refund.
policy_rejection refund_not_possible The payment intent has not succeeded, was not paid by card or cash, or can no longer be refunded.
policy_rejection refund_not_supported_by_provider The payment was made by QR, and its provider can’t refund it. Refund the customer another way, such as in cash, and keep a record of it.
policy_rejection refund_not_yet_available 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.
policy_rejection refunds_not_enabled Refunds are not enabled for your account with its card provider. Ask your platform operator to have them enabled.
Idempotency-Key
required
string
<= 255 characters

A value unique to this operation, such as your order number and attempt, of 1 to 255 characters. A retry with the same key and body is done at most once; see Idempotency.

Example
order-1042-attempt-1
Media typeapplication/json
object
payment_intent
required
string
amount

In the currency’s smallest unit. Leave it out to refund what remains.

integer
>= 1
reason
string
Allowed values: requested_by_customer duplicate fraudulent
metadata

Your own key-value pairs, returned as given and carried in webhooks: up to 50 keys of up to 40 characters without square brackets, each with a text value of up to 500 characters.

object
<= 50 properties
key
additional properties
string
<= 500 characters

The refund.

Media typeapplication/json
object
id
string
object
string
Allowed value: refund
payment_intent
string
amount
integer
currency

A three-letter ISO 4217 code, in lower case.

string
/^[a-z]{3}$/
status

created for the moment it is made, processing while it is on its way, then succeeded or failed. awaiting_approval while the platform’s risk team looks at it before it is sent: it then goes on, or fails as risk_declined. Nothing is refunded while it waits, and the amount stays held against what the payment has left to refund.

string
Allowed values: created processing awaiting_approval succeeded failed
reason
string | null
Allowed values: requested_by_customer duplicate fraudulent
failure_reason

Why it failed, when it did.

string | null
Allowed values: declined refund_not_possible refund_not_yet_available refunds_not_enabled restricted risk_declined unknown
metadata

Your own key-value pairs, returned as given and carried in webhooks: up to 50 keys of up to 40 characters without square brackets, each with a text value of up to 500 characters.

object
<= 50 properties
key
additional properties
string
<= 500 characters
livemode
boolean
created

A Unix timestamp.

integer
Example
{
"id": "re_01j9x3a1b2c3d4e5f6g7h8j9k0",
"object": "refund",
"currency": "php",
"status": "created",
"reason": "requested_by_customer",
"failure_reason": "declined",
"metadata": {
"order_id": "1042"
}
}

validation_failure: invalid_parameter for a parameter missing or not valid, named in param; invalid_json for a body that is not JSON; unsupported_media_type for a body that is not sent as JSON; not_acceptable when the request will not accept JSON; method_not_allowed for an HTTP method the path does not take.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure",
"code": "invalid_parameter",
"message": "A whole number of minor units, from 1 to 999999999999999999.",
"param": "amount",
"request_id": "req_4f1c0b2e9a7d"
}
}

authentication_failure: access_token_required when no token was sent, invalid_access_token when it is not valid, has expired, or is a client secret. Sent with a WWW-Authenticate: Bearer header, which adds error="invalid_token" when a token was sent.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

authorization_failure with merchant_mismatch: a Merchant-Id header, query parameter or body field names a merchant or tenant other than the key’s.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

not_found: resource_missing for an id this key cannot see, route_missing for a path that does not exist.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

conflict: intent_state when the intent is not in a state that allows this; idempotency_key_reused when the Idempotency-Key was used for a different request. timeout_or_in_progress with idempotency_key_in_use while a request with the same key is still running, or with refund_in_progress for a refund while another refund of the same payment is still being processed.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

policy_rejection: your account may not do this now, for the reason in code.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}

dependency_failure with service_unavailable: something on our side, or a payment network behind it, did not answer, or failed part-way. Whether the call took effect is not known, so do not assume it did not. Retry the same request with the same Idempotency-Key, and never make a new key for the retry: if the first call took effect, you are answered with its result (the payment intent or refund it made, or the intent as it now is) and nothing is done a second time. A retry refused with conflict and intent_state means the intent is no longer in a state that allows the call: the first call may have taken effect, or the customer may have acted since. Read the intent. If the failure came while the answer was being stored, the key is held for five minutes and a retry in that time answers 409 with idempotency_key_in_use: retry shortly. See When a write answers 503.

Media typeapplication/json
object
error
required
object
type
required
string
Allowed values: validation_failure authentication_failure authorization_failure not_found conflict timeout_or_in_progress policy_rejection invariant_violation rate_limited dependency_failure
code
required

A stable name for this refusal. Branch on this, never on message.

string
message
required

For the developer reading a log. May be reworded.

string
param
required

The field or parameter at fault, when there is one.

string | null
request_id
required
string | null
Example
{
"error": {
"type": "validation_failure"
}
}