Issue a refund

Return funds to a customer for a charge, a payment intent, or a paid invoice — in full or in part.

View as Markdown

A refund returns captured funds to the customer who paid them. You can refund a charge by its payment intent or by the invoice it paid, refund the full amount or only part of it, and record refunds that were already processed outside PaymentKit.

Create a refund

A refund always targets a single succeeded charge. You identify that charge in one of two ways:

  • payment_intent_id — refund the latest succeeded charge on a payment intent.
  • invoice_id — refund the charge that paid an invoice. PaymentKit resolves the payment allocation for you. (If the invoice was paid by more than one payment intent, refund by payment_intent_id instead.)

Provide at least one of these. If you supply both, payment_intent_id takes precedence.

  1. Open the Payment or Invoice you want to refund
  2. Click Refund
  3. Enter a full or partial amount and choose a reason
  4. Click Refund to send it to the processor

The refund appears immediately with a Pending status and updates to Succeeded once the processor confirms it.

Request fields

FieldTypeDescription
payment_intent_idstringThe payment intent to refund. Required unless invoice_id is provided.
invoice_idstringAn invoice to refund. PaymentKit resolves the charge that paid it. Required unless payment_intent_id is provided.
amount_atomintegerAmount to refund, in the smallest currency unit (e.g. cents). Must be greater than 0. Defaults to the full refundable amount.
currencystringCurrency code (e.g. USD). Defaults to the charge’s currency; if provided, it must match.
reasonstringOne of manual, duplicate, fraudulent, requested_by_customer, expired_uncaptured_charge, manual_out_of_band. Defaults to manual.
refunded_out_of_bandbooleanSet true to record a refund you already processed elsewhere (e.g. in the processor’s dashboard). No processor call is made and the refund is marked succeeded immediately. Defaults to false.
metadataobjectFree-form JSON, up to 10 KB.

Send an Idempotency-Key header on every create request. If the call is retried with the same key, PaymentKit returns the original refund instead of issuing a duplicate.

The refund object

1{
2 "id": "re_live_0a1b2c3d4e5f6g7h",
3 "account_id": "acc_live_...",
4 "charge_id": "ch_live_...",
5 "amount_atom": 1500,
6 "currency": "USD",
7 "status": "succeeded",
8 "reason": "requested_by_customer",
9 "processor_refund_id": "re_3Nz...",
10 "failure_code": null,
11 "failure_message": null,
12 "processed_at": "2026-06-17T14:05:00Z",
13 "metadata": null,
14 "created_at": "2026-06-17T14:04:58Z",
15 "updated_at": "2026-06-17T14:05:00Z"
16}
FieldDescription
idRefund identifier, prefixed re_.
charge_idThe charge that was refunded.
amount_atom / currencyThe refunded amount and its currency.
statusLifecycle status — see below.
reasonThe reason supplied at creation, if any.
processor_refund_idThe processor’s own refund ID. null for out-of-band refunds or while still pending.
failure_code / failure_messagePopulated when status is failed.
processed_atWhen the processor finished the refund. null while pending.

Refund statuses

StatusMeaning
pendingCreated and awaiting the processor’s response.
succeededFunds returned to the customer (or recorded out-of-band). Terminal.
failedThe processor rejected the refund. See failure_code / failure_message. Terminal.
requires_actionAdditional action is required before the refund can complete (rare). Non-terminal.
cancelledCancelled before completion — from pending or requires_action. Terminal.

Look up refunds

MethodPathReturns
GET/api/{account_id}/payments/refunds/{refund_id}A single refund
GET/api/{account_id}/payments/refunds/by_charge/{charge_id}All refunds for a charge (paginated)
GET/api/{account_id}/payments/refunds/by_intent/{payment_intent_id}All refunds for a payment intent (paginated)
$curl https://api.paymentkit.com/api/{account_id}/payments/refunds/by_intent/pi_abc123 \
> -H "Authorization: Bearer sk_live_..."

Rules and limits

  • The charge must have succeeded. You can only refund a charge in the succeeded state.
  • You cannot refund more than the refundable amount — the captured amount minus any refunds that have already succeeded. Fully-refunded charges have a refundable amount of 0.
  • Partial refunds are allowed as long as the running total stays within the refundable amount. Issue several partial refunds against the same charge until it is fully refunded.
  • Refunding an invoice payment reduces the paid amount on the linked invoice(s) accordingly.

Webhook events

EventTrigger
refund.createdA refund was created.
refund.updatedA refund field changed — including the transition to succeeded.
refund.failedThe refund was rejected. Includes failure_code and failure_message.

There is no dedicated refund.succeeded event. A successful refund surfaces as refund.updated carrying the new succeeded status.