Safe retries and orderNumber

API v1

The 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 doWhat happens
Retry with the same orderNumberDuplicate rejection, even if the first one went through
Retry with a new orderNumberRisk of double charge

On a network timeout there is no safe retry.

What to do instead#

Query the state before deciding:

  1. Call POST /api/v1/consult with the original orderNumber.
  2. If the transaction exists, use its result. Do not retry.
  3. 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  → retry

Design consequences#

  • Generate the orderNumber in 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 orderNumber from something that can repeat (recycled cart number, truncated timestamp, resettable counter).
  • A "Transacción duplicada" does not mean the charge failed: it means that orderNumber was already used. Query before showing the customer an error.

Last verified: 2026-08-28 · Owner: equipo-integraciones

View as raw Markdown