After the payment
Refunds
Refund a payment programmatically over the public merchant API. You can refund a payment in full or in part, and a partially-refunded payment can be refunded again (any number of times) until its full amount has been returned. Fees are not returned on a refund.
A refund only ever touches a payment that belongs to your account — the payment id is resolved within your own merchant scope, so you can never refund another merchant's payment.
Required API-key permissions
This endpoint is part of the public merchant API and is API-key-authenticated. It requires the payment.refund scope, which every key has by default. A TEST key refunds sandbox payments only; a payment of the other mode answers 404:
payment.refund— required forPOST /merchant/payment/:id/refund.
Authentication
Calls authenticate exactly like the rest of the API: exchange your key + secret for a short-lived access token via POST /merchant/api-auth/login (with the x-api-key / x-api-secret headers), then send that token as Authorization: Bearer <token>. See the Authentication section for the full flow.
Refund a payment — POST /merchant/payment/:id/refund
Requires the payment.refund scope.
:id is the payment's id — the same id returned when the payment (or secure-payment / embed checkout) was created, and the id listed by GET /merchant/payment.
Request body
amount(optional) — the amount to refund in major units (e.g.10.00), in the same currency as the original payment (for a sale the buyer paid in their own currency, the currency of your price; see Local Currency). Omit it for a FULL refund of the remaining refundable balance. Include it for a PARTIAL refund — it must be greater than zero and ≤ the remaining refundable balance.reason(optional) — a short note recorded with the refund (e.g."customer request").
Full refund (omit `amount`):
curl -X POST https://api.vezmo.com/api/v1/merchant/payment/PAYMENT_ID/refund \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "reason": "customer request" }'Partial refund (include `amount`):
curl -X POST https://api.vezmo.com/api/v1/merchant/payment/PAYMENT_ID/refund \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042-refund-1" \
-d '{ "amount": 10.00, "reason": "customer request" }'Retrying a refund
Send an Idempotency-Key header (1–255 ASCII characters) so a retry after a timeout can't refund twice:
- Same key and same body: you get the refund that was already made, and no second refund.
- Same key with a different body:
422“Idempotency key was reused with different parameters.” - The key is per payment. Use a new key for the next refund of the same payment.
Success response
201 Created:
{
"success": true,
"message": "Refund processed",
"data": {
"paymentId": "cmq17im8p0001abcd", // the payment that was refunded
"amount": 10.00, // amount refunded by THIS call
"currency": "USD",
"fullyRefunded": false, // true once the whole payment is refunded
"refundedTotal": 10.00, // running total refunded across all refunds
"status": "partially_refunded" // "refunded" | "partially_refunded"
}
}Field meanings:
amount— the amount returned by this specific call.refundedTotal— the cumulative amount refunded on this payment so far (including this call).fullyRefunded—truewhen this call exhausted the remaining refundable balance; the payment'sstatusbecomesrefunded. Otherwise it ispartially_refundedand you can refund the remainder later.
How long a refund takes, by payment method
A refund goes back the way the customer paid. Most methods return it in a few days and accept a refund only within a window after the payment:
| Paid with | Refund window | Reaches the customer |
|---|---|---|
| Card, Apple Pay, Google Pay | — | 5–10 business days |
| UPI | 60 days | Up to 7 business days |
| Pix | 90 days | Usually within minutes |
| Klarna | 180 days (not once a dispute has escalated) | 5–7 business days; Klarna cancels any payments still due |
| Affirm | 120 days | About 2 days; Affirm cancels the remaining payments (interest already paid is not returned) |
| Afterpay | 120 days | Up to 10 business days; Afterpay cancels the remaining payments |
| Amazon Pay | 90 days | Up to 14 days |
Those refunds finish after the call returns. If one fails, the amount comes back to your balance and you receive payment.refund_failed; refund the customer another way. A payment the buyer paid in their own currency is refunded in that currency (see Local currency).
Errors
The endpoint returns a clean, descriptive error in these cases:
404— the payment was not found (or does not belong to your account).422— the requestedamountexceeds the remaining refundable balance.400— an invalidamount(e.g. zero or negative), or the payment can't be refunded (for example: not a successful captured payment, already fully refunded, or under dispute).409— a refund of this payment is still running. Retry in a few seconds.503— refunds are temporarily unavailable. Retry later.401— missing or invalid access token.403— your API key lacks thepayment.refundpermission.
404 — payment not found.
{
"success": false,
"message": "Payment not found.",
"errors": [{ "code": "http.404", "message": "Payment not found.", "statusCode": 404 }],
"data": null,
"requestId": "…",
"timestamp": "…"
}422 — amount exceeds the refundable balance.
{
"success": false,
"message": "Refund amount exceeds the refundable balance ($12.50 remaining).",
"errors": [{ "code": "http.422", "message": "Refund amount exceeds the refundable balance ($12.50 remaining).", "statusCode": 422 }],
"data": null,
"requestId": "…",
"timestamp": "…"
}400 — payment can't be refunded. (e.g. it is under dispute, already fully refunded, or was never a successful capture.)
{
"success": false,
"message": "A disputed transaction cannot be refunded.",
"errors": [{ "code": "http.400", "message": "A disputed transaction cannot be refunded.", "statusCode": 400 }],
"data": null,
"requestId": "…",
"timestamp": "…"
}Test mode (sandbox)
Use a test API key against the same base URL https://api.vezmo.com — create a test payment, then refund it: omit amount for a full refund, or include it for a partial one and refund the remainder in a later call. Sandbox refunds work even while your account is still under review.
Keys and payments are mode-locked: a test key can only refund test payments, and a live key only live ones. Crossing modes returns 404 Payment not found — the same response as an unknown id.