Skip to content

Refunds ​

Automatic refunds ​

IIMMPACT creates refunds automatically.

ReasonAmountWhen
failed_fulfillmentSum of failed units' frozen sale prices, rounded to two decimals per unit; excludes customer fees.One aggregate refund against the order's winning payment, after all units finish.
duplicate_collectionEntire extra collection, including its customer fee.A separately confirmed duplicate collection; never fulfills the order again.

If the RM60 item succeeds and the RM40 item fails, the order gets one RM40 refund. If every item fails, IIMMPACT refunds the full item subtotal; the customer's fee share is not refunded. For quantity three with one failed unit, IIMMPACT refunds one unit's sale price. No refund is created when all units succeed.

Each duplicate collection gets its own refund. Refunds appear in the order's refunds array, in refund reads and in refund events, all in the schema below.

CARD refunds return to the card. FPX refunds, and card refunds the card rejects, go to requires_action until the customer claims them to a bank account.

A failed_fulfillment refund is deducted from your account balance before the customer is repaid. If your balance is too low, the refund stays pending and retries automatically. duplicate_collection refunds are not deducted from your balance.

Refund schema ​

FieldTypeDescription
refund_idstringStable identifier through processing, claim and review.
order_idstringOrder receiving the refund.
payment_idstringOriginal collection being repaid; not a per-item allocation.
reasonstringfailed_fulfillment or duplicate_collection.
amountstringPositive two-place refund amount.
currencystringMYR.
statusstringpending, requires_action, requires_review, or successful. See refund progress.
failureobjectOnly while requires_action after the bank rejected a transfer.
failure.codestringdestination_rejected.
failure.messagestringFor example The bank rejected the transfer to Maybank xxxx9012.
failure.destinationobjectThe rejected account, masked: type and display.
destinationobjectAfter a claim, while pending or successful: the receiving account, masked, with type (bank_account) and display.
actionobjectOnly on order and refund reads while requires_action; never in webhooks.
action.typestringredirect.
action.urlstringClaim page for the customer.
action.expires_atstringLink expiry, 15 minutes after the read. Read again for a new link.
created_atstringUTC refund creation time.
updated_atstringUTC time of the latest public refund change.

Refund example ​

json
{
  "refund_id": "01M4WJ0665EFKXS1ECZR7PBTM8",
  "order_id": "01M4WHY4KZVJ0APG07TFH7PM0W",
  "payment_id": "01M4WHY4T2VHJSJJXNFYA99Q0B",
  "reason": "failed_fulfillment",
  "amount": "10.00",
  "currency": "MYR",
  "status": "requires_action",
  "created_at": "2026-10-14T06:36:07.236Z",
  "updated_at": "2026-10-14T06:36:07.737Z",
  "action": {
    "type": "redirect",
    "url": "https://pay.iimmpact.com/refunds/claim#<token>",
    "expires_at": "2026-10-21T05:52:14.396Z"
  }
}

Refund progress ​

StatusMeaning
pendingWaiting for your balance, queued, or awaiting bank or provider confirmation.
requires_actionThe customer must choose a bank account. There is no deadline. After a bank rejection, failure explains why.
requires_reviewThe result is uncertain; IIMMPACT is reviewing it. It moves to successful, or back to requires_action if the customer was not paid.
successfulCustomer repayment is verified.

Order completed does not mean repayment finished; wait for refund successful, and do not refund a customer yourself while a refund is under review. The winning payment's merchant fee remains billable even when every unit fails.

Customer refund claims ​

When you receive refund.requires_action, the customer must choose the bank account for the refund. Either:

  • Use the IIMMPACT claim page: when the customer opens your refund screen, read the refund and redirect them to action.url at once. The link expires after 15 minutes, so do not email it. Or
  • Build your own screen with the claim endpoints.

The account must belong to the payer: IIMMPACT gets the holder name from the bank and compares it with the payer's name from the payment provider. Only when the provider reports none is the customer.name you sent used, so send the customer's real name. The full refund amount is always paid. After a claim the refund is pending until the bank confirms; a rejected transfer returns it to requires_action.

Get a refund ​

http
GET https://api.iimmpact.com/v2/refunds/{refund_id}

Returns the refund in data, including action while it is requires_action. Errors: 404 refund_not_found, 400 invalid_refund_id.

List refunds ​

http
GET https://api.iimmpact.com/v2/refunds?status=requires_action&limit=20

Optional query fields: order_id, payment_id, status, limit (1–100, default 20) and cursor (the previous page's next_cursor). Returns data.items newest first, without action, and data.next_cursor when more exist.

Claim endpoints ​

All use API Key + HMAC. customer_external_id is the customer's external_id from the payment. Never log full account numbers.

OperationEndpoint
List banksGET /v2/banks
List saved accountsGET /v2/refund-accounts?customer_external_id={id}
Check an accountPOST /v2/refund-accounts/lookup
Claim the refundPOST /v2/refunds/{refund_id}/claim
Remove a saved accountDELETE /v2/refund-accounts/{refund_account_id}?customer_external_id={id} (204)

GET /v2/banks returns a plain array of { "bank_name", "bank_code" }, without a data envelope.

Saved accounts are created by successful claims and returned in data as an array, newest first, each with refund_account_id, type, bank_code, display (masked), account_holder_name and is_default.

Check an account and show the returned holder name to the customer. account_number is 4–34 digits:

json
{
  "refund_id": "01M4WJ0665EFKXS1ECZR7PBTM8",
  "destination": { "type": "bank_account", "bank_code": "MBBEMYKL", "account_number": "123456789012" }
}
json
{
  "data": {
    "account_holder_name": "AMIRA BINTI HASSAN",
    "destination": { "type": "bank_account", "display": "Maybank xxxx9012" }
  }
}

Claim with { "destination": { ... } } (same shape, without refund_id) or { "refund_account_id": "..." }, never both. The bank check runs again on every claim. The response is data with refund_id, status: "pending" and the masked destination.

Each refund allows 10 bank checks per 24 hours, claims included.

HTTPCodeAction
400invalid_destinationFix the destination or account ID. Names and amounts are not accepted.
400invalid_customer_external_idSend the customer's external_id.
404refund_not_found, refund_account_not_foundNot found, removed, or another customer's.
409refund_not_claimableThe refund no longer needs customer action; read its status.
422payer_mismatchThe holder does not match the payer. Ask for the customer's own account.
422destination_not_foundThe bank cannot find this account.
429lookup_limit_reachedBank-check limit reached; try again later.
503lookup_unavailableBank check temporarily unavailable; retry later.

IIMMPACT API Documentation