Skip to main content

Refunds

POST /v1/refunds refunds a succeeded payment intent — in full or in part. Refund IDs use the vpr_test_* / vpr_live_* prefix.

Required key: secret key (vp_sk_*). Available in SDK 0.11.x.

Create a refund

Omit amount to refund the full remaining balance (the server computes captured − previously refunded). Pass an amount below the remaining balance for a partial refund.

curl https://checkout.vonpay.com/v1/refunds \
-H "Authorization: Bearer vp_sk_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "payment_intent": "vpi_test_abc123", "amount": 500 }'
const refund = await client.refunds.create({
paymentIntent: "vpi_test_abc123",
amount: 500, // omit for a full refund
});

Request

FieldTypeRequiredDescription
payment_intentstringID of the payment intent to refund (vpi_test_* / vpi_live_*). Optional, but you must supply exactly one parent reference — either payment_intent or transaction.
amountintegerMinor units; positive (≥ 1). Omit to refund the full remaining balance; pass a value below the remaining balance for a partial refund.
currencystring3-letter alphabetic ISO 4217 currency code.
reasonstringOne of duplicate, fraudulent, requested_by_customer, expired_uncaptured_charge. Mirrored back on the refund record.
metadataobjectObject with string keys and arbitrary JSON values.

Response — Refund

{
"id": "vpr_test_JL3xPcFktvsF10Ib",
"payment_intent": "vpi_test_abc123",
"amount": 500,
"currency": "USD",
"status": "succeeded",
"reason": null
}
FieldTypeDescription
idstringRefund record ID (vpr_test_* / vpr_live_*).
payment_intentstringThe payment intent this refund applies to.
amountintegerRefunded amount, in minor units.
currencystringISO 4217 (uppercase on response).
statusstringrequested, succeeded, failed, or canceled.
reasonstring | nullThe reason supplied on create, or null.

Status

A refund record is created in requested and reaches a terminal succeeded or failed; canceled is a rare terminal state.

requested ──▶ succeeded
└─▶ failed

Full vs. partial

  • Full — omit amount. Refunds captured − previously refunded.
  • Partial — pass an amount below the remaining refundable balance. The full-vs-partial outcome is determined by the amount relative to the remaining balance, not by whether amount is present.
  • Multiple partial refunds against the same intent are allowed up to the remaining refundable balance. Each issues a separate refund record and fires its own charge.refunded event.

Constraints

ConditionResult
amount exceeds the remaining refundable balance422 refund_amount_exceeds_remaining. The error envelope carries remaining_refundable.
The source intent is not in a refundable state (status is not succeeded)422 refund_intent_not_refundable. The error envelope carries payment_intent and current_status.

Void-after-capture

To reverse a captured intent, check the void_after_capture capability. When it is rerouted_to_refund, a void on a captured intent is handled through the refund pathway — call refunds.create rather than paymentIntents.void.

Reconciliation

Each refund fires a charge.refunded webhook carrying refund_id, amount (this refund), is_partial, and original_charge_amount. To get the cumulative refunded total for a charge, sum amount across all charge.refunded events for the same transaction_id.