Ir al contenido
SitioCrear cuenta

Guías

Idempotencia

Reintentá cualquier solicitud de escritura sin riesgo de emitir dos comprobantes, con el encabezado X-Idempotency-Key.

Una red inestable te deja sin saber si una solicitud llegó: el POST salió, pero la respuesta no volvió. Si reintentás a ciegas, podés emitir dos facturas por la misma venta, con dos consecutivos que ya no se pueden recuperar. La idempotencia resuelve eso.

Enviá un identificador único de la operación en el encabezado X-Idempotency-Key:

Terminal
curl https://aster.astranexo.com/api/v1/electronic-documents \
-H "Authorization: Bearer aster_test_8KfQ2mVx3TzL9pRw" \
-H "Content-Type: application/json" \
-H "X-Idempotency-Key: pedido-1042" \
--data @factura.json
Regla Detalle
Dónde aplica Todas las escrituras protegidas: POST, PUT, PATCH y DELETE
Largo Hasta 255 caracteres. Más largo responde 400 invalid_idempotency_key
Alcance Por organización y usuario de la llave. La misma llave en otra organización es otra operación
Duración 24 horas desde la primera solicitud

Lo que pasa cuando repetís la llave:

Situación Respuesta
Misma llave, mismo cuerpo y misma ruta, con la primera solicitud terminada La respuesta guardada, con el mismo código y cuerpo, y el encabezado Idempotent-Replayed: true. La solicitud no se ejecuta de nuevo
Misma llave mientras la primera solicitud todavía se procesa 409 idempotency_in_progress
Misma llave con otro cuerpo u otra ruta 422 idempotency_key_reused
La primera solicitud terminó con un 5xx Nada guardado: el reintento con la misma llave se ejecuta normalmente

Las respuestas 4xx sí se guardan. Si la primera solicitud falló por validación (422), repetirla con la misma llave devuelve el mismo 422. Corregí el cuerpo y usá una llave nueva, o el mismo identificador con un sufijo de versión.

La llave debe identificar la operación de negocio, no el intento:

Operación Llave recomendada
Facturar un pedido El ID del pedido: pedido-1042
Venta en un punto de venta Caja y número de transacción: caja3-venta-88120
Nota de crédito por una devolución El ID de la devolución: devolucion-1042-1
Mensaje Receptor La clave del comprobante del proveedor
Anular un comprobante anular- más el consecutivo o la clave

Evitá generar un UUID nuevo en cada intento: así cada reintento es una operación distinta y la protección desaparece. Si usás UUID, generalo una vez, guardalo junto al pedido y reutilizalo en todos los intentos.

enviar-con-reintentos.mjs
const API = 'https://aster.astranexo.com/api/v1/electronic-documents';
export async function emitir(pedido, body) {
const key = `pedido-${pedido.id}`; // la misma en todos los intentos
for (let intento = 1; intento <= 5; intento++) {
let res;
try {
res = await fetch(API, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.ASTER_API_KEY}`,
'Content-Type': 'application/json',
'X-Idempotency-Key': key,
},
body: JSON.stringify(body),
signal: AbortSignal.timeout(30_000),
});
} catch {
await esperar(intento); // red caída o timeout: reintentá con la misma llave
continue;
}
if (res.status === 409 || res.status === 429 || res.status >= 500) {
const retryAfter = Number(res.headers.get('Retry-After')) || 0;
await esperar(intento, retryAfter);
continue;
}
return res.json(); // 2xx o 4xx definitivo: no reintentes
}
throw new Error(`No se pudo emitir el pedido ${pedido.id}`);
}
function esperar(intento, segundos = 0) {
const ms = Math.max(segundos * 1000, 2 ** intento * 500);
return new Promise((r) => setTimeout(r, ms));
}

Reglas del patrón:

  • Reintentá ante errores de red, timeouts, 409 idempotency_in_progress, 429 rate_limited (respetando Retry-After) y 5xx.
  • No reintentes un 4xx distinto de 409 y 429: el resultado no va a cambiar.
  • Usá espera exponencial y un máximo de intentos.

La idempotencia evita que un reintento emita un segundo comprobante. Es independiente de la regla de Hacienda sobre los consecutivos: si numerás vos y enviás un consecutive_number que ya usaste, la respuesta es 409 duplicate_consecutive, con o sin llave de idempotencia. Ver consecutivo.