Safe retries and orderNumber
API v1The Tilopay API is not idempotent. There is no idempotency key and no retry that returns the original transaction. If you come from other processors, this is the assumption to dismantle before writing code.
orderNumber is unique forever#
orderNumber is unique per merchant across their entire operation, forever. It does not
reset daily, monthly or seasonally.
If it repeats, the new transaction is rejected with the response "Transacción duplicada" (duplicate transaction). It does not return the original transaction: it returns a rejection.
The timeout problem#
When a payment call dies on a network error or timeout, you do not know whether the transaction was created. And neither intuitive way out works:
| What you would do | What happens |
|---|---|
Retry with the same orderNumber | Duplicate rejection, even if the first one went through |
Retry with a new orderNumber | Risk of double charge |
On a network timeout there is no safe retry.
What to do instead#
Query the state before deciding:
- Call
POST /api/v1/consultwith the originalorderNumber. - If the transaction exists, use its result. Do not retry.
- If it does not exist, then you can retry — and you can reuse the same
orderNumber, because it was not consumed.
payment → timeout
│
└─→ consult(original orderNumber)
├─ exists → use that result
└─ not found → retryDesign consequences#
- Generate the
orderNumberin your system before calling the payment and persist it. If you generate it on the fly, after a timeout you have nothing to query with. - Never derive the
orderNumberfrom something that can repeat (recycled cart number, truncated timestamp, resettable counter). - A "Transacción duplicada" does not mean the charge failed: it means that
orderNumberwas already used. Query before showing the customer an error.
Last verified: 2026-08-28 · Owner: equipo-integraciones