Saltar al contenido
DevFact

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.

emitir-con-reintentos.jsJavaScript
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");
}