Facturiadocs
Errores

El sobre de error

La forma exacta de un error, los nueve tipos, qué hacer con cada uno y por qué el request_id importa.

Un error es un código HTTP más un solo objeto error. No hay sobre de éxito: las respuestas exitosas son el recurso.

{
  "error": {
    "type": "invalid_request_error",
    "code": "receptor_incomplete",
    "message": "Receptor 76543212-K is not in the SII contribuyente registry and no giro was supplied. Provide receptor.giro and receptor.address.",
    "param": "receptor.giro",
    "doc_url": "https://docs.facturia.cl/errors/receptor_incomplete",
    "request_id": "req_01K2R7Q9M4T2VB",
    "empresa": "77928532-4"
  }
}
CampoQué es
typeLa familia del error. Determina qué hacer
codeEl error específico, estable. Programa contra esto
messageProsa legible por una persona. No programes contra esto
paramEl campo del request que causó el problema, cuando aplica
doc_urlUn enlace a la explicación de este código
request_idEl identificador de esta llamada exacta
empresaEl RUT en cuyo contexto ocurrió
existing_idEn conflictos, el id del objeto que ya existe
siiPresente en sii_error — el estado crudo del SII

Los nueve tipos

typeHTTPSignificaQué hacer
invalid_request_error400Entrada mal formada o incompletaArregla el request. Reintentar igual no sirve
authentication_error401Llave ausente, revocada o mal formadaRevisa la credencial
permission_error403Llave válida, no permitida: scope, lista blanca de empresas, modoRevisa el scope o la empresa. error.message nombra el que falta
not_found_error404No existe ese objeto bajo esta llaveRevisa el id y el modo de la llave
conflict_error409Conflicto de estado: reuso de idempotencia, folio duplicado, empresa ya existenteMira existing_id
unprocessable_error422Bien formado pero viola una regla del dominio: folios agotados, ventana de acuse cerrada, empresa que aún no emiteEs una regla de negocio, no un bug de formato
rate_limit_error429Más lento; mira Retry-AfterEspera lo que dice el header
sii_error502El SII rechazó o falló la llamada de arriba. error.sii trae el estado y la glosa crudosVer Códigos
api_error500 / 503Nuestro. Nada se emitióReintenta con backoff

402 plan_limit_reached aparece cuando se agota una cuota de plan; el cuerpo nombra el límite y la URL para subir. El modo test nunca tiene límite por plan.

El request_id

Loguéalo siempre

request_id aparece en cada respuesta, exitosa o no, en el header Facturia-Request-Id. Con él podemos encontrar la llamada exacta. Sin él, una conversación de soporte empieza por reconstruir qué pasó.

Un cliente HTTP bien hecho lo guarda junto al resultado, no solo cuando algo falla.

Cómo manejar errores en la práctica

async function llamar(path, init) {
  const res = await fetch(`https://api.facturia.cl/v1${path}`, init);
  const requestId = res.headers.get('Facturia-Request-Id');

  if (res.ok) return { data: await res.json(), requestId };

  const { error } = await res.json();

  switch (error.type) {
    case 'rate_limit_error':
      // El header dice cuánto. No adivines.
      return { retryAfter: Number(res.headers.get('Retry-After') ?? 1), requestId };

    case 'api_error':
      // Nada se emitió. Reintenta con la MISMA Idempotency-Key.
      throw new Reintentable(error, requestId);

    case 'sii_error':
      // Puede ser transitorio. `error.sii` dice qué respondió el SII.
      throw new Reintentable(error, requestId);

    case 'invalid_request_error':
    case 'unprocessable_error':
      // Reintentar el mismo cuerpo va a fallar igual. Arréglalo o escálalo.
      throw new NoReintentable(error, requestId);

    default:
      throw new NoReintentable(error, requestId);
  }
}

Trampa

Un 4xx no quema tu Idempotency-Key; un 5xx sí es seguro de reintentar

Los requests que fallan con 4xx no consumen la llave de idempotencia: arregla el cuerpo y reintenta con la misma llave. Los fallos 5xx también son seguros de reintentar con la misma llave — esa es exactamente la situación para la que existe.

Lo que no debes hacer es generar una llave nueva al reintentar un timeout: ahí es donde nacen las facturas duplicadas.

El diccionario legible por máquina

curl https://api.facturia.cl/v1/error_codes

Sin autenticación. Devuelve cada código de Facturia, su contraparte del SII y si conviene reintentar. Es el mismo contenido que Códigos de rechazo, en una forma que tu build puede consumir.

En esta página