# Reintentos seguros y orderNumber

> El API no es idempotente. Qué hacer exactamente cuando una llamada de pago se cae por timeout.

- kind: concept
- status: stable
- api_version: v1
- last_verified: 2026-08-28
- url: https://www.tilopay.com/developers/concepts/reintentos-seguros

<Callout type="warn">
**El API de Tilopay no es idempotente.** No existe una llave de idempotencia ni un reintento
que devuelva la transacción original. Si venís de otros procesadores, este es el supuesto que
tenés que desarmar antes de escribir código.
</Callout>

## `orderNumber` es único para siempre [#ordernumber]

`orderNumber` es único por comercio **a lo largo de toda su operación**, para siempre. No se
reinicia por día, por mes ni por temporada.

Si se repite, **la nueva transacción se rechaza** con la respuesta **"Transacción
duplicada"**. No devuelve la transacción original: devuelve un rechazo.

## El problema del timeout [#timeout]

Cuando una llamada de pago se cae por red o por timeout, no sabés si la transacción se creó o
no. Y ninguna de las dos salidas intuitivas sirve:

| Qué harías | Qué pasa |
|---|---|
| Reintentar con el mismo `orderNumber` | Rechazo por duplicado, incluso si la primera sí pasó |
| Reintentar con un `orderNumber` nuevo | Riesgo de doble cobro |

**Ante un timeout de red no hay reintento seguro.**

## Qué hacer entonces [#que-hacer]

Consultá el estado antes de decidir:

1. Llamá a `POST /api/v1/consult` con el `orderNumber` original.
2. Si la transacción existe, usá su resultado. No reintentés.
3. Si no existe, ahí sí podés reintentar — y podés reusar el mismo `orderNumber`, porque no se
   consumió.

```text
pago → timeout
        │
        └─→ consult(orderNumber original)
              ├─ existe  → usar ese resultado
              └─ no existe → reintentar
```

## Consecuencias de diseño [#diseno]

- Generá el `orderNumber` en tu sistema **antes** de llamar al pago y persistilo. Si lo
  generás al vuelo, después de un timeout no tenés con qué consultar.
- Nunca derives el `orderNumber` de algo que se pueda repetir (número de carrito reciclado,
  timestamp truncado, contador reiniciable).
- Un "Transacción duplicada" no significa que el cobro falló: significa que ese
  `orderNumber` ya se usó. Consultá antes de mostrarle un error al cliente.
