Refund an Installment
Issue full or partial refunds for completed bank installment transactions. Amwal coordinates with the customer's issuing bank to adjust or cancel future installment billings.
Refund State Flow
A 200 response only means the refund was accepted — settlement
happens afterward and asynchronously. The diagram below covers request-time
validation, the P → R settlement path, the known issue with repeated
refunds on the same transaction, and the resulting status changes on both
the transaction and the payment link.
Multiple Partial Refunds (1-Hour Window)
When you submit multiple partial refund requests for the same transaction ID within one hour, the first request is marked as Refunded and subsequent requests are marked as Pending. This behavior is identical in both sandbox and live environments.
Endpoint
POST /transactions/refund/{transaction_id}/Trailing slash is required
The trailing slash after {transaction_id} is not optional. Omitting it
returns an HTTP redirect instead of processing the refund.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
transaction_id | String (UUID) | Yes | The unique Transaction UUID to refund (e.g. 60b43176-5991-4475-8ef6-c73c2417c805). |
Request Headers
Pass your merchant public key in the required X-Amwal-Key header:
- Sandbox:
X-Amwal-Key: sandbox-amwal-xxx - Production:
X-Amwal-Key: prod-amwal-xxx
Authorization: YOUR_SECRET_KEY
X-Amwal-Key: sandbox-amwal-xxx
Content-Type: application/json| Header | Type | Required | Description |
|---|---|---|---|
Authorization | String | Yes | Your Amwal Secret Key (e.g. <YOUR_SECRET_KEY_UUID>). |
X-Amwal-Key | String | Yes | Merchant Public Key (sandbox-amwal-xxx in Sandbox, prod-amwal-xxx in Production). |
Content-Type | String | Yes | Must be set to application/json. |
Request Body
{
"refund_amount": 100.00,
"reason": "Customer returned partial order items",
"metadata": {
"rma_number": "RMA-9842"
}
}Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
refund_amount | Number | Yes | Amount to refund in SAR. Rejected with 400 if it exceeds the transaction's remaining refundable balance. |
reason | String | No | Internal audit reason for the refund. |
metadata | Object | No | Optional merchant tracking metadata (e.g. rma_number). |
Response (200 OK)
{
"status": "success",
"key_type": "RefundReference",
"key": "2026001726"
}Response Parameters
| Field | Type | Description |
|---|---|---|
status | String | Outcome of the refund acceptance: "success". |
key_type | String | Reference identifier type: "RefundReference". |
key | String | Gateway-generated refund reference tracking number (e.g. "2026001726"). Use this reference for bank inquiry and audit tracking. |
key is the gateway's refund reference number. This response confirms the refund was accepted by the gateway. To inspect the resulting transaction state, remaining balance, and settlement progress, call
Get Payment Link Details or
Get Transaction Details. Once applied,
the transaction's status becomes partially refunded or refunded
(see Transaction Status), its
refunded_amount reflects the total refunded so far, and a refund_tracker
array is populated with one entry per refund (including the gateway
transaction id and RRN).
Settlement Is Asynchronous & Multiple Partial Refunds
A successful 200 response confirms that the refund request was accepted by Amwal. Settlement with the customer's issuing bank happens afterward.
Refund Tracker Statuses
You can inspect the status of each refund entry in the transaction's refund_tracker array:
refund_tracker[].status | Meaning | Description |
|---|---|---|
R | Refunded (Settled) | The refund has completed and settled. The bank's Retrieval Reference Number (rrn) is populated. |
P | Pending | The refund has been accepted and is queued for settlement at the card gateway or bank. |
Multiple Partial Refunds within One Hour
When you submit multiple partial refund requests for the same transaction ID within one hour:
- First Request: The first request is processed and marked as Refunded (
status: "R"upon settlement). - Subsequent Requests: Subsequent requests within that 1-hour window are accepted and marked as Pending (
status: "P"). - Consistent Behavior: This behavior is identical across both sandbox and live production environments.
{
"refund_tracker": [
{
"amount": 50.0,
"status": "R",
"rrn": "2026001726",
"created_at": "2026-09-02T10:00:00Z"
},
{
"amount": 25.0,
"status": "P",
"rrn": null,
"created_at": "2026-09-02T10:15:00Z"
}
]
}Tracking Settlement & Webhook Notifications
The top-level refunded_amount updates immediately with the sum of all accepted refund amounts. To monitor individual settlement transitions from P (Pending) to R (Refunded), inspect the refund_tracker array via Get Transaction Details or listen for order.updated webhook events.
Pending Refund Processing by Environment
- Live environment: The Finance team reviews pending refund requests and processes them as appropriate. You receive an
order.updatedwebhook notification when the refund status changes. If a refund remains pending for 24 business hours, contact Amwal support so we can take further action. - Sandbox environment: Pending refunds are not processed automatically. To test the related webhook event, share the transaction IDs with Amwal support so we can process the pending refunds.
Errors
| Status | Body | Cause |
|---|---|---|
400 | {"message": "Maximum amount to be refunded is <amount>", "validation_errors": [...], "fields_errors": []} | refund_amount exceeds the transaction's remaining refundable balance. |
400 | {"message": "Your balance is not sufficient to initiate any refund process. You can retry when you have a balance exceeding the amount you are trying to refund.", "validation_errors": [{"Name": "Supplier", "Error": "Insufficient balance for supplier <id>"}], "fields_errors": []} | merchant/supplier account does not have enough available balance to cover this refund — a separate check from the transaction-level remaining-balance one above. Retry once your balance is sufficient. |
400 | {"message": "The transaction is already under processing!", "validation_errors": [{"Name": "Key", "Error": "The transaction is already under processing!"}], "fields_errors": []} | A previous refund on this same transaction hasn't finished processing yet. Transient — retrying after a short delay (a few seconds) usually succeeds. See the "Refund State Flow" diagram above and "Settlement Is Asynchronous" section below. |
403 | {"detail": "You are not allowed to refund this transaction"} | transaction_id does not exist, or does not belong to the authenticated merchant. Note this is 403, not 404. |
403 | {"detail": "This transaction is not refundable"} | The transaction is outside the refund eligibility window — see "Refund Time Window" below. Same response shape as the row above; check how old the transaction is to tell the two apart. |
Important Notes
| Topic | Detail |
|---|---|
| Sufficient balance | Your merchant account must have enough available balance to process a refund (see the "Insufficient balance for supplier" error above). |
| Online refunds | Typically take 3–5 business days to settle once accepted. |
| Bank installment refunds | Processing time varies, usually 5–7 business days. |
| Refund time window | Refunds are only accepted within 60–90 days of the original transaction. An older transaction returns 403 {"detail": "This transaction is not refundable"}. |
| Reference tracking | Keep the key value from the 200 response — it's the gateway's refund reference and is what customer service will need to look up the refund later. |
Get Transaction Details
Retrieve complete transaction-level authorization data, partner bank installment approval, card details, fee breakdowns, and refund tracker history.
Resolve Installment Link
Resolve online installment payment links when customers access payment URLs via mobile apps or direct browser sessions.
