Documentación
Idempotencia y reintentos
Reintenta sin duplicar comprobantes ni gastar números.
Idempotency-Key
Si una petición se corta (timeout, caída de red), no sabes si el comprobante se creó. Envía una Idempotency-Key única por operación de tu sistema (el id de la venta, del pedido…) y repite la petición con la misma clave: recibes el mismo comprobante, con la cabecera Idempotent-Replayed: true, sin gastar otro número.
- Hasta 255 caracteres imprimibles. Vale 7 días.
- La misma clave con otro cuerpo responde
409 IDEMPOTENCY_CONFLICT: usa una clave nueva para cada comprobante distinto. - Sin clave, cada petición crea un comprobante nuevo, con su propio número.
Reintentar bien
Reintenta sólo lo que tiene sentido: cortes de red, 429 y 503. Un 422 necesita una corrección y un 202 ya está en manos del servicio.
async function emitir(cuerpo, idVenta) {
for (let intento = 1; intento <= 5; intento++) {
try {
const res = await fetch("https://api.devfact.fonles.com/v1/facturas", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DEVFACT_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": `venta-${idVenta}`, // la misma en cada intento
},
body: JSON.stringify(cuerpo),
signal: AbortSignal.timeout(30_000),
});
if (res.status !== 429 && res.status !== 503) return { status: res.status, datos: await res.json() };
const segundos = Number(res.headers.get("Retry-After")) || 2 ** intento;
await new Promise((r) => setTimeout(r, segundos * 1000));
} catch {
// Red o timeout: la misma clave evita duplicar si el servidor sí la recibió.
await new Promise((r) => setTimeout(r, 2 ** intento * 1000));
}
}
throw new Error("La API no respondió; reintenta más tarde con la misma Idempotency-Key");
}
