Refund a card charge
Request a full or partial refund and confirm when funds have been returned.
API Refs
- Staging: Refund a card charge
POST /api/public/card-charges/{id}/refunds
Include your API key in the Authorization header and send JSON. Funds return to the original card, not an alternative bank account or payment method.
Request body
| Name | Type | Description | Required |
|---|---|---|---|
amount | integer | Principal to refund in cents, excluding surcharge. Omit it to refund the remaining refundable principal in full. Must be positive and cannot exceed the remaining refundable amount. | no |
idempotencyKey | string | Unique key for this refund, up to 255 characters. Reuse the same key when retrying this request. Strongly recommended to avoid duplicate attempts. | no |
Full refund request
{
"idempotencyKey": "order-123-full-refund"
}For a partial refund, supply amount. Any original surcharge is refunded proportionally, with the final portion taking the remaining surcharge to account for rounding. Do not add the surcharge to the requested principal yourself.
Pending is not completed
HTTP 201 means the refund request was accepted or an existing refund was returned on replay. Inspect the returned status; an accepted request may still be processing.
Illustrative pending response for a $1 refund:
{
"id": 9,
"chargeId": 14,
"status": "processing",
"refunded": {
"principalCents": 0,
"surchargeCents": 0,
"totalCents": 0
},
"failureCode": null,
"failureMessage": null,
"createdAt": "2026-09-11T02:48:03.114Z"
}While a refund is processing, refunded contains zero confirmed returned funds. A previously succeeded charge remains succeeded unless another confirmed refund has already changed its state. Pending amounts are reserved against the refundable balance, but are not reported as returned. Failed refunds also report zero confirmed returned funds.
Confirm completion
Subscribe to card_charge_refund_status_changed (event ID 8) and card_charge_status_changed (event ID 7). When the refund completes, the refund status is succeeded and its confirmed returned amounts become nonzero. The charge becomes refunded for a full refund or partially_refunded for a partial refund.
The refund webhook includes both the original receipt and the separate confirmed refunded amounts. GET the charge to retrieve its refund history and reconcile current state with Moov. Processing time is asynchronous; do not assume completion immediately after POST or after a fixed delay.
Illustrative completed refund, as returned within GET's refunds array or by a successful same-key replay:
{
"id": 9,
"chargeId": 14,
"status": "succeeded",
"refunded": {
"principalCents": 100,
"surchargeCents": 0,
"totalCents": 100
},
"failureCode": null,
"failureMessage": null,
"createdAt": "2026-09-11T02:48:03.114Z"
}Retry safely and handle failures
Repeat the same refund request using the same idempotencyKey. A successful replay preserves the original refund id and createdAt and returns the current stored status rather than a frozen copy of the first response. Linked pending refunds are refreshed on a best-effort basis during replay; use GET when you need the provider-validation read. Replays can therefore show succeeded after the original response showed processing, without creating another refund.
| Result | What to do |
|---|---|
HTTP 400 | Correct invalid input, such as a nonpositive or noninteger amount. |
HTTP 404 | Check the charge ID and the account associated with your API key. |
HTTP 422 | The refund was rejected or is not allowed, for example when the charge is already fully refunded. Inspect the error before creating another attempt. |
HTTP 502 with code: "REFUND_OUTCOME_UNKNOWN" | The processor outcome is uncertain. Do not assume no money moved and do not switch to a new key. Reuse the original key and reconcile or contact support if the outcome remains unresolved. |
Processor-rejected refunds use REFUND_REJECTED; failed refunds without a more specific code use REFUND_FAILED. A replay of a failed or unresolved attempt returns the corresponding handled error rather than a successful refund response. Validation errors may have a message without a refund failure code.
Updated 21 days ago