Un integrador robusto trata los errores como un escenario esperado, no como una excepción. Esta guía agrupa los patrones que necesitas implementar para producir una integración estable contra la API y el SRI.
Clasifica el error por origen
Antes de reaccionar, decide en cuál de estas tres categorías cae el error:
- Cliente — tu petición está mal (4xx). No reintentes; corrige.
- Servidor / infraestructura — 429, 503, timeouts. Reintenta con backoff.
- SRI — recepción o autorización rechazada. Lee el detalle, corrige y reemite.
Patrón general (pseudocódigo)
javascript
async function call(method, path, body) {
const res = await fetch(BASE + path, {
method,
headers: { 'X-API-Key': KEY, 'Content-Type': 'application/json' },
body: body ? JSON.stringify(body) : undefined,
});
if (res.status === 204) return null;
const payload = await res.json();
if (res.ok) return payload.data ?? payload;
// Map by HTTP status
if (res.status === 401 || res.status === 403) throw new AuthError(payload);
if (res.status === 422) throw new ValidationError(payload);
if (res.status === 404) throw new NotFoundError(payload);
if (res.status === 429) throw new RateLimitError(payload, res.headers.get('Retry-After'));
if (res.status >= 500) throw new UpstreamError(payload);
throw new ApiError(payload);
}Validación previa
- Antes de un
POST /documents, valida quebusiness_id,customer_ideitems[].item_idexistan en tu lado. - Confirma que la fecha del comprobante esté dentro de la ventana aceptada por el SRI (no a más de N días vista, según resolución vigente).
- Asegúrate de que el cliente tenga
emailantes de llamar aemail:send.
Cómo leer un Problem Details
json
{
"type": "about:blank",
"title": "Unprocessable Entity",
"status": 422,
"detail": "El RUC del cliente no es válido.",
"errors": [
{ "field": "customer_id", "message": "El RUC del cliente no es válido." }
],
"instance": "urn:uuid:9f2c..."
}errors[].field es exactamente el nombre del campo que falló: úsalo para resaltar el input correspondiente en tu UI, o para construir un mapa de validación.
Reintentos con backoff
javascript
async function withRetry(fn, { tries = 5 } = {}) {
let delay = 1000;
for (let attempt = 1; attempt <= tries; attempt++) {
try {
return await fn();
} catch (err) {
const retriable =
err instanceof RateLimitError ||
err instanceof UpstreamError ||
err.name === 'TimeoutError';
if (!retriable || attempt === tries) throw err;
const wait = err.retryAfter
? Number(err.retryAfter) * 1000
: delay;
await new Promise(r => setTimeout(r, wait));
delay *= 2;
}
}
}Errores específicos del SRI
| Mensaje típico | Significado | Acción |
|---|---|---|
| "FIRMA INVÁLIDA" | El certificado .p12 está vencido o corrupto. | Sube una firma nueva en POST /businesses/{id}/files. |
| "CLAVE DE ACCESO REGISTRADA" | El SRI ya recibió un comprobante con la misma clave. | Consulta el documento (GET /documents/{id}) y procede como si ya estuviera emitido. |
| "SECUENCIAL EN USO" | Otro comprobante en el SRI ya usó ese número. | Alinea el secuencial con PUT /sequences/{id} y reemite. |
| "RECEPCIÓN PENDIENTE" | Aún no hay respuesta de autorización. | Llama PUT /documents/{id} con { "verify": true } tras unos minutos. |

