Referencia
Catálogo de errores
Todos los códigos de error de la API v1, la API de socios y Conectar, con su causa y qué hacer, y los rechazos y observaciones de SUNAT más comunes explicados.
Actualizado el
Cuando algo sale mal, la respuesta trae siempre un code estable y un message en español:
{
"success": false,
"code": "validacion",
"message": "Revisa los datos enviados.",
"errors": { "totales.total_venta": ["El campo totales.total venta es obligatorio."] }
}
- Decide por el
code, nunca por el texto del mensaje: el texto puede mejorar, el código no cambia. - Muestra el
messagea tu usuario si te sirve: está pensado para leerse. errorsaparece en las validaciones, con los campos que fallaron.- En los 5xx no hay detalles internos. Reintenta con la misma
Idempotency-Key.
API v1
Autenticación y permisos
| HTTP | code |
Causa | Qué hacer |
|---|---|---|---|
| 401 | clave_invalida |
Falta la clave o no existe | Envíala en Authorization: Bearer <clave> |
| 401 | clave_revocada |
La revocaron | Crea otra en Configuración › Sistema › Integraciones › API |
| 401 | clave_vencida |
Pasó su fecha de vencimiento | Crea otra o usa una sin vencimiento |
| 401 | clave_en_url |
La mandaste en la URL o en el cuerpo | Solo en la cabecera Authorization |
| 401 | clave_de_pruebas |
Una clave sfp_test_ fuera del modo pruebas |
Usa pruebas.sistemafacturacionperu.com o una clave sfp_live_ |
| 401 | token_invalido, token_vencido |
Conectar: el token no sirve o venció | Renuévalo con tu token de renovación |
| 401 | conexion_revocada |
Conectar: la empresa desconectó tu aplicación | Pídele que vuelva a conectar |
| 401 | aplicacion_suspendida |
Conectar: suspendimos tu aplicación | Escríbenos |
| 403 | scope_faltante |
La clave no tiene el alcance (cabecera X-SFP-Scope-Required) |
Crea una clave con ese alcance |
| 403 | sin_permiso |
El usuario de la clave no tiene esa función | Dale la función al usuario o usa otra clave |
| 403 | plan_sin_api |
El plan no incluye la API | La API viene desde el Plan PRO |
| 403 | plan_insuficiente |
Conectar en Básico: esa función viene desde PRO (errors.plan, cabecera X-SFP-Plan-Required) |
La empresa sube de plan; no hace falta reconectar |
| 403 | establecimiento_no_permitido |
La clave tiene un local fijo y pediste otro | Usa una clave sin local fijo o la de ese local |
| 423 | cuenta_bloqueada |
Pago vencido o cuenta suspendida | La empresa regulariza su pago |
Petición
| HTTP | code |
Causa | Qué hacer |
|---|---|---|---|
| 400 | json_invalido |
El cuerpo no es JSON | Revisa el JSON y Content-Type: application/json |
| 400 | idempotencia_invalida |
La Idempotency-Key está mal formada |
Hasta 255 caracteres visibles; usa un UUID |
| 400 | peticion_invalida |
La petición está mal armada | Revisa método, cabeceras y cuerpo |
| 404 | no_encontrado |
No existe o tu clave no lo puede ver | Revisa el id; en pruebas, cada clave ve solo lo suyo |
| 404 | cdr_no_disponible |
El comprobante aún no tiene constancia de SUNAT | Espera a que esté aceptado |
| 404 | archivo_no_disponible |
El PDF o XML no está disponible | Reintenta en unos segundos |
| 405 | metodo_no_permitido |
Método equivocado para esa dirección | Revisa la referencia |
| 409 | idempotencia_distinta |
Misma Idempotency-Key con otro cuerpo |
Usa una clave nueva para cada operación distinta |
| 409 | idempotencia_en_proceso |
La primera petición con esa clave aún corre | Reintenta en unos segundos con la misma clave |
| 409 | duplicado |
Ya existe (un comprobante con esa serie y número, un cliente con ese documento…) | Consulta el que existe |
| 409 | ya_anulado |
Ya está anulado o en proceso de anulación | Nada: consulta su estado |
| 409 | no_reenviable |
No se puede reenviar a SUNAT (ya está aceptado, por ejemplo) | Consulta su estado |
| 413 | cuerpo_muy_grande |
El cuerpo es demasiado grande | Envía menos datos por llamada |
| 422 | validacion |
Faltan datos o tienen otro formato (detalle en errors) |
Corrige los campos de errors |
| 429 | demasiadas_solicitudes |
Más de 120 llamadas por minuto con la clave | Espera los segundos de Retry-After |
| 429 | demasiadas_emisiones |
Más de 30 emisiones por minuto | Espera Retry-After; reparte las emisiones |
Reglas del negocio (422)
code |
Causa | Qué hacer |
|---|---|---|
limite_plan |
El plan ya no permite emitir más este ciclo | La empresa sube de plan o espera el siguiente ciclo |
serie_invalida |
La serie no corresponde al tipo de comprobante o al local | Usa una de GET /establecimientos |
establecimiento_no_existe |
No hay un local con ese código | Revisa GET /establecimientos |
almacen_invalido |
El almacén no es del local | Usa uno de los almacenes del local |
producto_no_existe |
Con control de stock, el codigo_interno no existe |
Créalo con POST /productos |
stock_insuficiente |
No alcanza el stock | Revisa GET /stock |
lote_no_disponible, lote_sin_stock |
El lote no existe o no tiene stock | Usa otro lote |
serie_no_disponible, series_cantidad |
Un número de serie no está disponible o no son tantos como la cantidad | Manda una serie por unidad |
regla_de_inventario |
Otra regla del inventario (el mensaje dice cuál) | Sigue el mensaje |
detraccion_minimo |
La detracción no aplica a ese monto | Quítala o activa «Detracción para montos menores» |
detraccion_con_retencion |
Detracción y retención del IGV juntas | Quita la retención |
detraccion_operacion |
Detracción con una operación que no es 1001-1004 | Usa 1001 (o 1004) |
detraccion_codigo |
El código de detracción no existe o está desactivado | Actívalo en Ventas › Configuración › Detracciones |
anticipo_no_existe, anticipo_sin_saldo |
El anticipo no existe, no es de anticipo, está anulado o no tiene saldo | Revisa la serie-número y el saldo |
regimen_no_permite |
SUNAT no permite ese comprobante a tu régimen (por ejemplo, facturas en el Nuevo RUS) | Emite el comprobante que te corresponde |
ficha_ruc_pendiente |
Falta verificar la Ficha RUC de la empresa | Súbela en Configuración › Empresa › Régimen tributario |
deuda_vencida |
El cliente tiene deuda vencida y la empresa restringe la venta | Cobra la deuda o cambia la regla en la empresa |
nota_credito_excede |
La nota de crédito pasa lo que queda del comprobante | Baja el importe |
documento_afectado_no_existe |
El comprobante que la nota modifica no existe | Revisa documento_afectado |
origen_no_existe, origen_no_permitido, nota_venta_no_facturable |
El origen (cotización, pedido, nota de venta o guía) no existe o no se puede facturar | Revisa origen |
no_anulable, va_en_resumen |
No se puede anular o reenviar (las boletas van en el resumen diario) | Ver Anular |
no_cobrable, cobro_excede_saldo, cobro_invalido |
El cobro no corresponde o pasa el saldo | Revisa GET /comprobantes/{id}/cobros |
limite_webhooks |
Ya tienes 10 webhooks | Borra uno para crear otro |
certificado_faltante |
Falta el certificado digital | Súbelo en Configuración › Empresa › Certificado |
ubigeo_invalido |
El ubigeo no existe | Usa el código INEI de 6 dígitos |
sunat_rechazo |
SUNAT rechazó el comprobante (el mensaje trae su código) | Ver errores de SUNAT |
regla_de_negocio |
Otra regla (el mensaje dice qué hacer) | Sigue el mensaje |
Servicios externos
| HTTP | code |
Causa | Qué hacer |
|---|---|---|---|
| 500 | error_interno |
Falla nuestra | Reintenta con la misma Idempotency-Key; si se repite, escríbenos con la hora |
| 502 | envio_fallido |
El correo o el WhatsApp no salió | Revisa el destino o la línea de WhatsApp de la empresa |
| 502 | sunat_no_responde |
SUNAT no respondió | Reintenta más tarde |
| 502 / 503 | consulta_no_disponible, no_disponible |
El servicio de consultas (RUC, DNI, tipo de cambio) no respondió | Reintenta más tarde |
Empresas de un socio
Además, la API v1 de una empresa dada de alta por un socio puede responder:
| HTTP | code |
Causa |
|---|---|---|
| 402 | saldo_agotado |
El saldo del socio es 0 y la empresa envía por nuestro PSE: no se creó nada |
| 402 | cuota_pendiente |
El socio tiene una cuota mensual vencida |
| 423 | suspendida_por_socio |
El socio pausó la emisión por API de esa empresa |
| 423 | socio_suspendido |
La cuenta del socio está suspendida |
API de socios
| HTTP | code |
Causa |
|---|---|---|
| 400 | json_invalido, idempotencia_invalida |
La petición está mal armada |
| 400 | grant_no_soportado |
POST /token solo acepta client_credentials |
| 400 | secreto_en_url |
Mandaste el secreto en la URL |
| 401 | credenciales_invalidas |
El client_id o el client_secret no sirven (o la credencial se revocó) |
| 401 | token_invalido, token_vencido, token_en_url |
El token no sirve, venció (dura 1 hora) o fue en la URL |
| 403 | socio_suspendido |
Tu cuenta de socio está suspendida |
| 403 | ip_no_permitida |
La credencial está limitada a otras IP |
| 404 | no_encontrado |
No existe o no es tuya (nunca decimos si existe) |
| 409 | ruc_ya_registrado |
Ese RUC ya tiene cuenta en el sistema (no decimos de quién) |
| 409 | empresa_creandose |
El alta todavía corre (con Retry-After) |
| 409 | empresa_con_error |
El alta falló: escríbenos con el id |
| 409 | idempotencia_distinta, idempotencia_en_proceso |
Conflicto con la Idempotency-Key |
| 422 | validacion |
Datos que corregir (detalle en errors) |
| 422 | certificado_invalido |
El .pfx no abre con su clave |
| 422 | regla_de_negocio |
Otra regla (el mensaje dice cuál) |
| 429 | demasiadas_solicitudes, demasiados_intentos |
Espera Retry-After segundos |
| 500 | error_interno |
Falla nuestra: reintenta |
La API antigua de reseller (api/reseller/*) responde 410 api_retirada: usa la API de socios.
Conectar (OAuth 2.0)
POST /oauth/token y POST /oauth/revoke responden con el formato estándar de OAuth (RFC 6749 §5.2):
{"error": "…", "error_description": "…"}.
| HTTP | error |
Causa |
|---|---|---|
| 400 | invalid_request |
Falta un parámetro o mandaste las credenciales de dos formas |
| 400 | invalid_grant |
El código o el token de renovación no sirve: vencido, ya usado, de otra aplicación, otra redirect_uri o PKCE que no corresponde |
| 400 | invalid_scope |
Pediste al renovar un permiso que la empresa no concedió |
| 400 | unsupported_grant_type |
Solo authorization_code y refresh_token |
| 401 | invalid_client |
client_id o client_secret equivocados, o tu aplicación está suspendida |
| 429 | temporarily_unavailable |
Demasiadas llamadas: espera Retry-After |
En la ventana de conexión, los errores vuelven a tu redirect_uri como ?error=invalid_request|invalid_scope|access_denied…
(salvo si el client_id o la redirect_uri no están registrados: entonces se muestran en la pantalla y no redirigimos).
Errores de SUNAT
Cuando SUNAT responde, su código queda en sunat.codigo del comprobante (y en el mensaje de sunat_rechazo). SUNAT
agrupa sus códigos así:
| Rango | Qué significa |
|---|---|
0 |
Aceptado |
0100 a 1999 |
Excepciones: SUNAT no procesó el envío (credenciales, archivo, servicio caído). Corrige y vuelve a enviar el mismo comprobante. |
2000 a 3999 |
Rechazo: el comprobante no es válido. Corrige y emite otro (con otro número). |
4000 en adelante |
Observaciones: el comprobante es válido (observado), pero corrige el dato para los siguientes. |
Los que más aparecen, en palabras simples:
| Código | SUNAT dice | Qué significa y qué hacer |
|---|---|---|
0102, 0103, 0104 |
Usuario o contraseña incorrectos / el usuario no existe / la clave es incorrecta | El usuario secundario SOL o su clave están mal. Revísalos en Configuración › Empresa › Datos y facturación SUNAT. |
0105 |
El usuario no está activo | Activa el usuario secundario en SUNAT Operaciones en Línea. |
0111 |
No tiene el perfil para enviar comprobantes electrónicos | Al usuario secundario le falta el perfil de emisión electrónica: dáselo en SUNAT Operaciones en Línea. |
0112 |
El usuario debe ser secundario | Usa un usuario secundario, no el principal. |
0109, 0130 |
El sistema no puede responder su solicitud | SUNAT está caído o lento. Reintenta más tarde (POST /comprobantes/{id}/reenviar-sunat en facturas). |
0127 |
El ticket no existe | El ticket de una guía, baja o resumen no está en SUNAT. Consulta otra vez en unos minutos. |
1032 |
El comprobante ya está informado y se encuentra anulado o rechazado | Ese número ya no sirve: emite uno nuevo. |
1033 |
El comprobante fue registrado previamente con otros datos | Ese número ya está en SUNAT con otros datos: consulta su CDR o emite con el siguiente número. |
2010, 2011 |
El contribuyente no está activo / no está habido | El RUC del emisor tiene problemas en SUNAT. Revisa la Ficha RUC. |
2017 |
El número de documento de identidad del receptor debe ser RUC | Una factura va a un cliente con RUC. Para un DNI, emite una boleta. |
2108 |
Presentación fuera de fecha | Se envió fuera del plazo de SUNAT. |
2329 |
La fecha de emisión se encuentra fuera del límite permitido | La fecha es muy antigua o futura: emite con la fecha de hoy. |
2335 |
El documento electrónico ingresado ha sido alterado | La firma no coincide (el certificado o el XML cambió). Vuelve a emitir. |
2640 |
Operación gratuita, solo debe consignar un monto referencial | La línea gratuita tiene precio cobrado: ver gratuitas. |
2800, 2801, 2802 |
El tipo o el número de documento del receptor no es válido | Revisa codigo_tipo_documento_identidad y el número (un DNI tiene 8 dígitos). |
3249 |
Si la venta es al crédito, debe existir al menos una cuota | Agrega las cuotas en una venta a crédito. |
4001 |
El número de RUC del receptor no existe | Observación: el comprobante vale, pero revisa el RUC del cliente con GET /consultas/ruc/{ruc}. |
4287 |
El precio unitario difiere de los cálculos | Observación: revisa valor_unitario, precio_unitario y el IGV de la línea. |
4332 |
El código de producto SUNAT no es válido | Observación: revisa codigo_producto_sunat del producto. |
Un comprobante observado es válido: no lo anules por una observación.