Ir al contenido

Errores ​

Todos los endpoints de /api/v1/* devuelven el mismo sobre de error. El campo error.code es estable: puedes ramificar tu lógica sobre él sin miedo a que cambie dentro de la v1.

Los endpoints OAuth2 /oauth/token y /oauth/revoke usan el formato de error del protocolo (por ejemplo, {"error":"invalid_grant"} si el código o refresh token no es válido), no este sobre de la API pública. Consulta Autenticación y scopes.

El sobre ​

json
{
  "error": {
    "type": "validation_error",
    "code": "invoice.nif_receptor_invalid",
    "message": "NIF del receptor no tiene formato válido",
    "param": "partner.id_num"
  }
}
CampoDescripción
typeCategoría general del error (ver tabla).
codeCódigo estable, legible por máquina. Ramifica sobre este.
messageTexto orientativo para depurar. No lo parsees.
detailsDatos estructurados específicos del error. Opcional.
paramCampo implicado, cuando aplica. Opcional.

Categorías (type) ​

typeHTTPSignificado
validation_error400El cuerpo o los parámetros no son válidos.
authentication_error401Credencial ausente, inválida o caducada.
permission_error403Falta el scope, o el recurso no admite la operación.
not_found_error404El recurso no existe en tu tenant.
conflict_error409 · 422Choque con el estado actual (duplicado, recurso en uso). También 422 al reutilizar una Idempotency-Key con otro cuerpo.
billing_error402El plan alcanzó un límite de uso.
verifactu_error422La operación es válida en forma pero la AEAT la rechazaría (desglose incoherente, destinatario no censado, emisión/remisión imposible).
internal_error500Error inesperado del servicio.

Códigos por categoría ​

Autenticación (401) ​

codeCuándo
api_key.missingNo se envió la cabecera Authorization.
api_key.invalidLa key no existe o fue revocada.
api_key.no_scopesLa key es válida pero no tiene ningún scope asignado.
oauth.invalid_tokenEl access token OAuth es inválido, expiró o fue revocado.

Permisos (403) ​

codeCuándo
api_key.insufficient_scopesLa key no tiene el scope que exige el endpoint.
oauth.insufficient_scopesEl token OAuth no tiene el scope requerido.
mutability.invoice_lockedIntentas editar/borrar una factura que no está en borrador.
plan_permission_requiredEl plan del tenant no incluye la funcionalidad.

Límite del plan (402) ​

plan_limit_reached incluye en details la metric, plan_code, limit, used y, para métricas mensuales, reset_at. No reintentes la misma operación hasta liberar stock, empezar un nuevo mes o cambiar de plan.

Validación (400) ​

codeCuándo
invalid_bodyEl JSON no valida contra el esquema del endpoint.
param.invalid_uuidUn UUID de la ruta está mal formado.
pagination.invalid_cursorEl cursor no es un cursor válido.
invoices.partner_requiredEl tipo de factura exige partner_id y no se envió.
idempotency.key_too_longLa cabecera Idempotency-Key supera los 255 caracteres.

No encontrado (404) ​

invoice.not_found, invoice_line.not_found, partner.not_found, product.not_found, serie.not_found, tax.not_found, economic_activity.not_found, verifactu_record.not_found, external_invoice.not_found.

Conflicto (409) ​

codeCuándo
partner.external_id_takenOtro partner ya usa ese external_id.
partner.id_num_takenOtro partner ya usa ese NIF/identificación.
product.external_id_takenOtro producto ya usa ese external_id.
product.name_takenOtro producto ya usa ese nombre.
serie.code_takenYa existe una serie con ese code.
serie.in_useLa serie tiene facturas o presupuestos (borradores incluidos) y no se puede borrar.
serie.numbering_startedLa serie ya numeró un documento: su numeración queda fijada, solo cambian name e is_active.
serie.type_immutableEl type se fija al crear la serie y no se puede cambiar.
serie.last_of_typeNo puedes borrar la última serie de un tipo.
economic_activity.in_useLa actividad está referenciada por facturas.
economic_activity.last_activityNo puedes borrar la última actividad del tenant.
idempotency.request_in_progressOtra petición con la misma Idempotency-Key sigue procesándose. Reintenta luego.
issuance_authorization_requiredLa cuenta todavía no tiene habilitada la emisión.
external_invoices_not_enabledLa cuenta no tiene habilitado Verifactu Direct API.

Idempotencia: cuerpo reutilizado

Reutilizar una Idempotency-Key con un cuerpo distinto devuelve 422 con code: idempotency.key_reused_with_different_body. Usa una clave nueva por operación. Ver Convenciones → Idempotencia.

Verifactu / no procesable (422) ​

type: verifactu_error. La petición es válida en forma pero la AEAT la rechazaría, así que se corta en origen: desglose incoherente, factura simplificada que supera el límite, o —con validar_cliente— un NIF de destinatario no identificado en el censo de la AEAT. El message describe la causa concreta.

Reglas de inmutabilidad

serie.in_use y mutability.invoice_locked reflejan la misma idea: lo que ya es un documento fiscal (factura emitida, serie con numeración usada) no se reescribe. Ver Ciclo de vida y Series.

Manejo recomendado ​

  • Ramifica sobre error.code, nunca sobre message.
  • En 401/403, revisa la key y sus scopes; no reintentes con la misma.
  • En 409, el estado del servidor ya no admite tu petición: léelo y reconcilia (p. ej. ante external_id_taken, usa el PUT de upsert).
  • En 422 al emitir, la factura sigue en borrador: corrige y reintenta.
  • Con Idempotency-Key: 409 idempotency.request_in_progress → reintenta en unos segundos; 422 idempotency.key_reused_with_different_body → usa una clave nueva por operación (ver Idempotencia).

Bilteo · Documentación