Errores y soluciones
Los errores más frecuentes de la API y de AEAT, y exactamente qué hacer con cada uno.
Errores HTTP de nuestra API
Estos errores los devolvemos nosotros antes de llegar a AEAT:
| Código | Cuándo | Qué hacer |
|---|---|---|
400 Solicitud incorrecta |
Validación fallida (campo faltante, formato incorrecto) | Lee el campo details en la respuesta — indica qué campo falla y por qué |
401 No autorizado |
API key ausente o inválida | Comprueba el header x-api-key y que la clave no esté revocada |
402 Pago requerido |
Límite de plan alcanzado | Consulta GET /me/plan — ver Plan y uso; escribe a soporte@simplefactu.com para ampliar |
403 Prohibido |
Permiso (scope) insuficiente o cuenta suspendida | Comprueba que tu API key tiene el permiso (scope) necesario para ese endpoint |
409 Conflicto |
Conflicto de encadenamiento o idempotencia | Lee la sección de errores 409 más abajo |
422 Entidad no procesable |
Certificado obligatorio, NIF no autorizado o cert ≠ allowed_nif |
Ver sección 422 más abajo |
429 Demasiadas solicitudes |
Límite de tasa superado | Espera Retry-After segundos e inténtalo de nuevo |
502 Puerta de enlace incorrecta |
AEAT devolvió un error o no respondió | El job se reintentará automáticamente con espera creciente; espera o consulta el estado |
504 Tiempo de espera agotado |
Timeout antes de recibir respuesta | La petición puede que haya llegado; usa la misma x-idempotency-key para reintentar sin duplicar |
Errores 422
details.code / code |
Cuándo | Qué hacer |
|---|---|---|
tenant_certificate_required |
QA/prod sin PFX en la cuenta | Sube el certificado con POST /me/certificate — Autenticación |
allowed_nif_mismatch |
El nif del body no coincide con el NIF autorizado del cuenta hija |
Usa el NIF fijado al crear el autónomo (gestoría) |
cert_nif_mismatch |
El PFX subido no corresponde al allowed_nif |
Sube el certificado del mismo titular |
wrong_passphrase |
Contraseña del PFX incorrecta | Revisa la passphrase del .p12/.pfx |
malformed |
El archivo no es un PKCS#12 válido | Comprueba que es .p12/.pfx, no PEM suelto |
legacy_rc2 |
Certificado FNMT antiguo (RC2-40) que no se pudo normalizar | Convierte con OpenSSL legacy — Autenticación |
expired |
Certificado caducado | Renueva en la FNMT y vuelve a subir |
Errores 409 — los más comunes en integración
ChainContinuityError
{
"error": "ChainContinuityError",
"expectedHuella": "910204E9...",
"receivedHuella": "AABBCC..."
}
Causa: la huella que pasaste en encadenamiento.registroAnterior.huella no coincide con la última huella que tenemos registrada para esa cadena.
Solución: la respuesta incluye expectedHuella — es exactamente la huella que debes usar. Cópiala en encadenamiento.registroAnterior.huella, o omite encadenamiento para que el servidor use la última huella de la cadena.
ChainStateError — la cadena ya existe
Causa: enviaste primerRegistro: true pero la cadena ya tiene facturas registradas.
Solución: omite primerRegistro (el servidor infiere el estado) o envía primerRegistro: false. Si controlas la cadena a mano, usa la huella de la última factura aceptada. Si no la tienes, omite encadenamiento para auto-relleno, o escríbenos con el requestId.
Idempotency conflict
Causa: reutilizaste una x-idempotency-key con un cuerpo diferente (factura distinta).
Solución: genera un UUID nuevo para cada factura nueva (uuidgen / crypto.randomUUID()). La misma clave solo debe reutilizarse si estás reintentando exactamente la misma petición (mismo body) tras un fallo de red. Ver Autenticación → Idempotencia.
Errores AEAT (dentro del job)
Cuando AEAT rechaza una factura, el job puede pasar a FAILED (reintento programado) o DEAD (agotados los intentos) y el resultado incluye el código de error original. Estos son los más frecuentes:
| Código | Nivel | Qué significa | Qué hacer |
|---|---|---|---|
1239 |
Registro | NIF del destinatario no existe en AEAT | Pide al cliente que corrija su NIF; re-emite con nueva x-idempotency-key |
2000 |
Registro | Huella incorrecta | El mensaje de error incluye la cadena canónica que AEAT calculó — úsala para depurar el formato de tus importes (ver abajo) |
4102 |
Envío | XML no cumple el esquema XSD | Falta un campo obligatorio; el más común es PrimerRegistro cuando primerRegistro: true |
4104 |
Envío | NIF del emisor no identificado | Tu NIF no está dado de alta o está mal escrito |
4109 |
Envío | NIF del sistemaInformatico incorrecto |
Con el camino normal (SIF Simple*Factu) no deberías verlo: contacta soporte. Si tienes clientSifEnabled, el NIF del bloque que envías debe existir en AEAT |
4116 |
Envío | NIF del obligado de emisión incorrecto | El campo nif del body no existe en AEAT |
Desglose (detalles) — validación 400 antes de AEAT
Si el body solo lleva base (u omite clave / calif), la API responde 400 con details[] (no llega a Hacienda). Códigos AEAT de referencia en el mensaje:
| Código | Qué falla | Qué hacer |
|---|---|---|
1195 |
Falta calif y causaExencion |
Envía uno de los dos |
1196 |
Ambos calif y causaExencion |
Solo uno (XOR) |
1198 |
calif=S2 con tipo/cuota ≠ 0 |
Pon tipo y cuota a 0 |
1208 |
calif=S1 sin tipo/cuota |
Añade tipo y cuota (salvo baseImponibleACoste) |
1237 / 1238 |
N1/N2 o exenta con tipo/cuota/recargo | Omite esos campos |
1281 / 1284 |
Recargo mal usado | Solo con S1 y ambos campos de recargo juntos |
| — | Falta clave en IVA/IGIC |
Añade clave (p. ej. "01") si impuesto omitido/01/03 |
Guía: Envío de facturas → Desglose.
Depurar el error 2000 (huella incorrecta)
Este error casi siempre viene de un problema de formato de importes. AEAT incluye en el mensaje de error la cadena canónica que ELLOS calcularon. Compara con la tuya:
AEAT calculó: ...CuotaTotal=21.0&ImporteTotal=121.0...
Tú enviaste: ...CuotaTotal=21.00&ImporteTotal=121.00...
↑
Sobra el segundo cero
Regla: un decimal si el segundo es cero (21.0), dos si no (21.15). Ver Conceptos clave → Formato de importes.
Si un job llega a DEAD
DEAD significa que el sistema agotó los 8 reintentos. La factura no fue aceptada por AEAT.
Para resolverlo:
- Lee
lastErroren el resultado del job (GET /jobs/:jobId) para entender el motivo. - Corrige el problema en tu sistema (NIF incorrecto, formato de importe, etc.).
- No puedes reenviar la misma factura con el mismo
numSerieuna vez que AEAT la ha rechazado definitivamente. Debes emitir una factura rectificativa (tipoR1–R5) que corrija la original. - Si el job llegó a
DEADpor un error transitorio (timeout de AEAT, red), escribe a soporte@simplefactu.com con eljobId/requestIdpara un reintento manual (operadores:POST /admin/jobs/:jobId/retrysolo si el estado esFAILED).
FAILED frente a DEAD
| Estado | ¿Terminal? | Qué hacer |
|---|---|---|
FAILED |
No | El proceso en segundo plano reintentará con espera creciente. Sigue consultando el estado. |
DEAD |
Sí | Agotó reintentos. Corrige la causa y emite nueva factura / rectificativa; no reutilices el mismo trabajo. |
SUCCEEDED |
Sí | Lee result.qrInfo (CSV + QR). |
Cada respuesta incluye un requestId
Guárdalo siempre que algo falle. Con ese UUID podemos ver la traza completa del envío, el XML que se envió a AEAT y la respuesta exacta. Escríbenos a soporte@simplefactu.com con el requestId.