Amwal Tech logoDocs

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 PR 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.

Rendering diagram...

The 2nd+ refund path is a known, open issue

Repeated refunds on the same transaction have been observed getting stuck at status: "P" indefinitely — see the "Settlement Is Asynchronous" section further down this page for what to check for and how to work around it in the meantime.


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

ParameterTypeRequiredDescription
transaction_idString (UUID)YesThe unique Transaction UUID to refund (e.g. 60b43176-5991-4475-8ef6-c73c2417c805).

Request Headers

Authorization: YOUR_SECRET_KEY
X-Amwal-Key: sandbox-amwal-xxx
Content-Type: application/json
HeaderTypeRequiredDescription
AuthorizationStringYesYour Amwal Secret Key (e.g. d9ccf8bc-ed63-44ad-a54c-9d8fee63df6b).
X-Amwal-KeyStringNoMerchant publishable API Key or sandbox identifier.
Content-TypeStringYesMust be set to application/json.

Request Body

{
  "refund_amount": 100.00,
  "reason": "Customer returned partial order items",
  "metadata": {
    "rma_number": "RMA-9842"
  }
}

Request Parameters

FieldTypeRequiredDescription
refund_amountNumberYesAmount to refund in SAR. Rejected with 400 if it exceeds the transaction's remaining refundable balance.
reasonStringNoInternal audit reason for the refund.
metadataObjectNoOptional merchant tracking metadata (e.g. rma_number).

Response (200 OK)

{
  "status": "success",
  "key_type": "RefundReference",
  "key": "2026001726"
}

Response Parameters

FieldTypeDescription
statusStringOutcome of the refund acceptance: "success".
key_typeStringReference identifier type: "RefundReference".
keyStringGateway-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 — a 200 Means "Accepted," Not "Settled"

A successful response only confirms the refund request was accepted. The actual gateway settlement happens afterward, and you should confirm it by reading the matching entry in refund_tracker:

refund_tracker[].statusMeaning
PPending — the refund has been accepted but has not settled at the gateway yet. rrn is null at this stage.
RSettled — the refund has completed. rrn (the bank's retrieval reference number) is populated.

refunded_amount can overstate what has actually settled

The transaction's top-level refunded_amount increases as soon as a refund request is accepted, not once it settles — it sums every accepted refund_amount, regardless of whether the corresponding refund_tracker entry ever reaches status: "R". Do not treat refunded_amount alone as proof that money has been returned to the customer; check that the specific refund_tracker entry has settled.

Issuing more than one refund against the same transaction is where this matters most. The first refund on a transaction settles normally. A second (or third) refund attempted shortly after the first may be rejected with 400 "The transaction is already under processing!" — retrying after a short delay usually succeeds. However, that acceptance is not a guarantee of settlement: repeated refunds on the same transaction have been observed staying at status: "P" indefinitely (no rrn, and no order.updated webhook ever fires for that entry), while refunded_amount still reflects the full accepted total. If you need to issue more than one refund on a transaction, poll Get Payment Link Details and verify each refund_tracker entry individually rather than relying on refunded_amount or webhook delivery alone.


Errors

StatusBodyCause
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

TopicDetail
Sufficient balanceYour merchant account must have enough available balance to process a refund (see the "Insufficient balance for supplier" error above).
Online refundsTypically take 3–5 business days to settle once accepted.
Bank installment refundsProcessing time varies, usually 5–7 business days.
Refund time windowRefunds are only accepted within 60–90 days of the original transaction. An older transaction returns 403 {"detail": "This transaction is not refundable"}.
Reference trackingKeep 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.

On this page