Idempotency
Use merchant references to retry requests without duplicating them.
The Business API has no Idempotency-Key header. Idempotency comes from merchant_reference, a value of up to 64 characters that you choose. The older reference field is an alias, and merchant_reference wins if you send both.
| Endpoint | merchant_reference |
|---|---|
POST /virtual-accounts/static | Required |
POST /virtual-accounts/dynamic | Required |
POST /transfers | Optional, strongly recommended |
POST /vas/pay/* | Optional, strongly recommended |
POST /bulk-transfers | Optional, strongly recommended |
POST /scheduled-bulk-transfers | Optional, strongly recommended |
POST /bulk-transfers/{id}/submit is safe to repeat without a reference. If the bulk transfer has already been submitted, you get its current state and the X-Idempotency-Replay: true header.
Customers and OTP requests aren't idempotent, so check for an existing record before you retry them.
What happens on a repeat
Payinto compares the new request with the original, scoped to your business and environment.
| Repeat request | Result |
|---|---|
| Same reference, same payload | 200 with the original result and the header X-Idempotency-Replay: true. Nothing new is created. |
| Same reference, different payload | 409 Duplicate merchant reference with a different payload. |
| New reference | Processed as a new request. |
Choose a good reference
Derive the reference from your own record, so a retry always produces the same value:
payout-10002
order-10001-va
invoice-2026-0042Avoid random values generated at request time, because each retry would get a new one and could pay twice.
Where a reference is required, a missing or blank value returns 422. Test and live references are separate.