Refunds
Issue full or partial refunds against completed payment sessions.
Before you begin
Refunds are merchant-initiated. They can only be issued against sessions in SUCCEEDED state. Kadosei automatically routes the refund to the provider that processed the original payment; you do not need to specify a provider.
Refund states
A refund moves through the following lifecycle states:
| State | Description |
|---|---|
| PENDING | Submitted to the provider, awaiting confirmation. |
| COMPLETED | The provider confirmed the refund was processed. Funds are being returned to the customer. |
| FAILED | The provider rejected the refund. A refund.failed webhook is delivered with the reason where available. |
Effect on the payment session
Issuing a refund updates the parent session state:
-
Full refund: session transitions from
SUCCEEDEDtoREFUNDED. -
Partial refund: session transitions from
SUCCEEDEDtoPARTIALLY_REFUNDED. The remaining refundable balance is updated. -
When cumulative partial refunds equal the original amount: session transitions from
PARTIALLY_REFUNDEDtoREFUNDED.
Create a refund
The Idempotency-Key header is required. Use a unique value per refund request to prevent duplicates on retry. If a request with the same key was already processed, Kadosei returns the existing refund record.
POST /api/v1/sessions/{sessionId}/refunds
Idempotency-Key: your-unique-key
{
"amount": 45.00,
"reason": "REQUESTED_BY_CUSTOMER",
"lineItems": [
{
"name": "Wireless Headphones",
"sku": "WH-100",
"quantity": 1,
"unitPrice": 45.00
}
]
}
All fields except Idempotency-Key are optional. Omit amount to refund the full remaining balance. lineItems are informational only, Kadosei stores them against the refund record but does not validate them against the original session or the refund amount.
{
"refundId": "3d72f30c-2977-44bf-b2e8-ff09b9b3216d",
"sessionId": "6a2fca3f-fffd-4f3a-8eaf-11af4e21aa7b",
"status": "PENDING",
"amount": 45.00,
"currency": "AUD",
"reason": "REQUESTED_BY_CUSTOMER",
"createdAt": "2026-04-24T12:30:00.000Z"
}
A 201 response means the refund has been submitted to the provider. Final confirmation of whether the refund succeeded or failed arrives via webhook. A 202 response means the refund was accepted and is being processed asynchronously and the outcome will also arrive via webhook.
A PENDING status in the response does not mean the refund is complete. Listen for refund.completed or refund.failed webhook events to confirm the outcome and update your records accordingly.
Webhook events
| Event | Description |
|---|---|
| refund.completed | The provider confirmed the refund was processed successfully. |
| refund.failed | The provider rejected the refund. The failureReason field in the payload indicates the cause where available. |
Errors
| Status | Cause |
|---|---|
| 400 | Missing Idempotency-Key header, or request validation failed (e.g. amount below 0.01). |
| 404 | Session not found. |
| 409 | A request with this idempotency key is already being processed. Wait retryAfter seconds and retry. |
| 422 | Session is not in a refundable state, the requested amount exceeds the remaining refundable balance, or the idempotency key was previously used with different parameters. |