Refund Transaction API

Refund one collection payment via SePay API, for money that arrived without any VA order behind it. No order lookup is needed.

||

Refund a transaction

POST
https://userapi.sepay.vn/v2/transactions/{transaction_id}/refund

Use this when money arrived with no order behind it, for example a transfer straight into the real account or into a registered static VA.

Get transaction ids from List transactions.

VietinBank enterprise accounts only for now

Refunds currently apply to VietinBank enterprise accounts. An account at another bank returns 422 unsupported_bank; an account that has not been enabled returns 422 not_available. The Sandbox does not apply this gate, so a refund that works there can still return 422 not_available in production.

X-Idempotency-Key is required

Without the header SePay returns 422 idempotency_key_required. Replaying the same key returns the existing record instead of moving money a second time.

How it runs

Transaction Refund Flow
Rendering diagram...

Steps 1, 6 and 10 on your side are the same as the order route: see Idempotency and reconciliation.

Step 3 also settles which bank handles it, since the bank comes from the account that received the payment. When the payment belongs to a VA order, that order is still recorded and the budget is shared with the order route.

Path parameters

transaction_idstringrequired

Collection transaction id, from List transactions

Headers

X-Idempotency-Keystringrequired

A dedup key you generate, unique per refund request, at most 100 characters. Replaying the same key returns the existing record instead of moving money twice. A longer key answers 422 validation_error with the error on idempotency_key.

Request body

refund_amountinteger

Amount to refund (VND, positive integer). Omit it to refund the whole remaining amount of the original payment.

Payments that do have an order still work here

When the payment belongs to a VA order, that order is still recorded as the refund's subject and the budget is shared with Refund an order. Using the other route cannot pay the money out twice.

Code Examples

>
>
>
>
>
>
curl --request POST \
--url https://userapi.sepay.vn/v2/transactions/6398452/refund \
--header 'Authorization: Bearer REPLACE_BEARER_TOKEN' \
--header 'X-Idempotency-Key: refund-order-DH20250001-01' \
--header 'content-type: application/json' \
--data '{"refund_amount":50000}'

Response (HTTP 200)

Response 200 - Refund request accepted
{
  "status": "success",
  "data": {
    "refund_id": "RF-7QK3-M8PZ-4VNW",
    "order_type": "va_order",
    "order_id": "string",
    "order_code": "string",
    "xid": "string",
    "transaction_id": "string",
    "original_reference": "string",
    "amount": 50000,
    "currency": "VND",
    "scope": "full",
    "status": "pending",
    "created_at": "2026-08-28 14:05:00"
  }
}
statusstring
dataobject

Errors

HTTPerror_codeDescription
404transaction_not_foundTransaction not found, or not owned by the authenticated company
409idempotency_key_reusedThis X-Idempotency-Key was already used for a different refund request. Use a new key.
422idempotency_key_requiredThe X-Idempotency-Key header is missing, or the key is longer than 100 characters
422not_availableSePay has not opened refunds on this account. Contact SePay.
422unsupported_bankThis account's bank does not support refunds
422unsupported_currencyThe bank cannot refund the original payment's currency
422not_refundableThis payment cannot be refunded
422no_original_transactionThe original collection payment was not found
422already_refundedThe original payment is already fully refunded
422unsupported_amount_precisionThe original amount cannot be represented in its currency
422validation_errorrefund_amount is invalid, or above the remaining amount
422refund_declinedThe bank declined the refund
422refund_duplicate_referenceThe refund reference already exists at the bank
422refund_amount_invalidThe amount is not valid for the original payment
422refund_failedThe bank accepted the request but could not complete it
422refund_rejectedThe bank did not accept the refund
500unexpected_errorA fault on SePay's side, not in your request. The refund may already have reached the bank, so look it up via List refunds or resend the same key, never a new one.
503refund_busyAnother refund for the same original payment is in progress. No record was created; retry in a few seconds with the same key.
503vietinbank_map_connection_errorSePay could not reach VietinBank. The refund record exists and is pending; SePay reconciles it on its own. Resend the same key to get that record back, never a new one.