Integración con SUNAT en 2025: lo que nadie te dice antes de empezar
La facturación electrónica en Perú lleva años siendo obligatoria para la mayoría de negocios. Y sin embargo, cada proyecto que la requiere trae sorpresas nuevas. Este artículo es el que hubiera querido leer antes de integrarla por primera vez.
El ecosistema real: SUNAT no es el único actor
El primer malentendido: pensar que se integra “directamente con SUNAT”. La realidad es más compleja.
Existen tres rutas para emitir comprobantes electrónicos:
1. SEE — Sistema de Emisión Electrónica directo de SUNAT Gratuito. XML firmado y enviado directamente a los servidores de SUNAT. Confiable cuando funciona, pero SUNAT tiene ventanas de mantenimiento frecuentes y los endpoints tienen uptime inferior al 99.9%.
2. OSE — Operador de Servicios Electrónicos Empresas certificadas por SUNAT que actúan como intermediarios. Tienen SLA, soporte técnico y endpoints más estables. Las más usadas: Nubefact, SUNAT Direct (de Nubefact), FacturaSunat, Holded.
3. PSE — Proveedor de Servicios Electrónicos Para contribuyentes de alto volumen que quieren procesar directamente. No aplica para la mayoría de proyectos que construimos.
Nuestra recomendación: para proyectos nuevos, usar Nubefact como OSE. Su API REST está bien documentada, el sandbox funciona, y tienen soporte técnico que responde el mismo día.
El XML UBL 2.1: más difícil de lo que parece
El estándar de SUNAT es UBL 2.1, que en teoría es internacional. En la práctica, SUNAT tiene extensiones propias y validaciones adicionales que no están en el estándar UBL.
Ejemplo real: el campo cbc:Note puede tener varias instancias, pero el orden importa. Si el total en letras va antes del tipo de operación, SUNAT rechaza el documento con un error críptico que dice “E-0007: El tipo de operación no es correcto”.
Las librerías Python para generar UBL:
factura-electronica-peru— funcional pero mantenimiento irregular- Generar el XML desde plantillas Jinja2 — más verboso pero control total
Nosotros optamos por las plantillas Jinja2 para tener control preciso del formato. El XML resultante se firma con la librería signxml.
La firma digital: el cuello de botella operacional
Todo comprobante electrónico requiere firma digital con el certificado de la empresa emisora. Esto implica:
- El cliente debe tener un certificado digital vigente (costoso: ~$150-300 USD/año)
- El certificado debe estar accesible para el servidor que genera los XMLs
- Si el certificado expira y nadie lo renueva, la facturación se detiene
El problema de seguridad: el certificado (archivo .p12 o .pfx con su clave) no puede vivir en el repositorio. Debe estar en variables de entorno o en un vault. En Railway usamos los secrets del proyecto; en Cloudflare Workers, usamos el KV o el environment secrets.
from signxml import XMLSigner, methods
from lxml import etree
def firmar_xml(xml_str: str, cert_path: str, key_path: str) -> bytes:
"""
Firma un comprobante UBL 2.1 con el certificado del contribuyente.
Usa el método XMLDSig enveloped, requerido por SUNAT.
"""
root = etree.fromstring(xml_str.encode())
signer = XMLSigner(
method=methods.enveloped,
digest_algorithm='sha256',
)
signed = signer.sign(
root,
key=open(key_path, 'rb').read(),
cert=open(cert_path, 'rb').read(),
)
return etree.tostring(signed, xml_declaration=True, encoding='UTF-8')
Los errores más frecuentes en producción
Después de integrar facturación electrónica en cinco proyectos, estos son los errores que aparecen con mayor frecuencia:
“0156 — El RUC no existe o no está activo” Ocurre cuando el RUC del receptor está dado de baja o inactivo en SUNAT. No es un bug — el usuario ingresó un RUC incorrecto o el proveedor cerró su empresa. Solución: validar el RUC antes de generar el comprobante usando la API de consulta de SUNAT.
“2075 — Las series utilizadas no corresponden al punto de emisión” Cada punto de emisión (local del negocio) tiene series asignadas. Si el sistema genera F001-1, F001-2… pero el punto de emisión solo tiene autorizada la serie F002, SUNAT rechaza todos los comprobantes. Hay que registrar los puntos de emisión en el panel de SUNAT antes de empezar a emitir.
Timeout en envío a SUNAT El endpoint de SUNAT puede tardar hasta 30 segundos en responder durante horas pico. Nunca enviar el XML de forma síncrona en el request del usuario. El patrón correcto:
- Guardar el comprobante en DB con estado
pending - Responder al usuario inmediatamente
- Tener un worker (Celery) que envía a SUNAT en background
- Actualizar el estado según la respuesta:
accepted,rejected,error - Reintentar automáticamente los errores transitorios con backoff exponencial
Baja de comprobantes: más complejo que la emisión
La baja (anulación) de un comprobante emitido tiene su propio flujo:
- Generar un XML de baja referenciando el comprobante original
- Firmarlo y enviarlo a SUNAT
- SUNAT procesa la baja en su batch nocturno — no es inmediato
- Al día siguiente, se consulta el estado de la baja
El punto crítico: no se puede revertir una baja. Si se anuló por error, hay que emitir un nuevo comprobante.
Tabla de comprobantes y sus particularidades
No todos los comprobantes se comportan igual ante SUNAT. Conocer las diferencias evita sorpresas:
| Comprobante | Uso | Particularidad |
|---|---|---|
| Factura (F) | Operaciones con RUC (crédito fiscal) | Requiere validar que el RUC del receptor esté activo |
| Boleta (B) | Consumidor final | Se puede enviar en resumen diario, no una por una |
| Nota de crédito | Anular o ajustar a la baja | Debe referenciar el comprobante original |
| Nota de débito | Ajustar al alza (intereses, moras) | Debe referenciar el comprobante original |
| Guía de remisión | Traslado de mercadería | Flujo y catálogos propios, distinto a facturación |
El resumen diario de boletas es clave para retail: en lugar de enviar miles de boletas individuales en tiempo real, se acumulan y se envía un resumen, lo que reduce drásticamente la carga sobre SUNAT y sobre tu sistema.
Cómo probar sin arriesgar datos reales
Un error común es desarrollar contra el ambiente de producción de SUNAT desde el inicio. No lo hagas. SUNAT y los OSE ofrecen un ambiente de pruebas (beta/sandbox) con RUC de prueba (por ejemplo 20000000001). Todo el desarrollo y QA debe correr ahí. Recién cuando el flujo completo funciona —emisión, baja, consulta de estado, manejo de errores— se cambia la configuración al ambiente de producción. Mantén las credenciales de ambos ambientes en variables de entorno separadas para no confundirlas: emitir una factura real de prueba contra producción genera un comprobante válido que luego hay que dar de baja.
Guía de inicio rápido
Si estás empezando una integración hoy:
- Crea una cuenta en Nubefact, configura el sandbox y prueba con RUC de prueba
20000000001 - Descarga los archivos de ejemplo de SUNAT (están en el portal de SUNAT como “Anexos”)
- Valida tu XML contra el esquema XSD antes de enviarlo — ahorra ciclos de debugging
- Implementa el flujo asíncrono desde el inicio — no trates de hacerlo síncrono “por ahora”
- Guarda siempre el XML enviado Y la respuesta de SUNAT — son la única evidencia ante una auditoría
La facturación electrónica en Perú no es sencilla, pero tampoco es imposible. Con las herramientas correctas y el patrón asíncrono bien implementado, puede funcionar con confiabilidad alta en producción.
Preguntas frecuentes
¿Cómo se integra la facturación electrónica con SUNAT?
Hay tres rutas: el SEE directo de SUNAT (gratuito pero con uptime menos confiable y mantenimientos frecuentes), un OSE u Operador de Servicios Electrónicos como Nubefact (intermediario certificado con SLA y soporte, la opción que recomendamos para proyectos nuevos), y el PSE para contribuyentes de altísimo volumen. La mayoría de proyectos integran vía un OSE con API REST documentada.
¿Qué es el XML UBL 2.1 y por qué da problemas?
Es el estándar de comprobantes que exige SUNAT. En teoría es internacional, pero SUNAT añade extensiones y validaciones propias que no están en el estándar UBL: por ejemplo, el orden de ciertos campos importa, y un orden incorrecto produce errores crípticos. Por eso muchos equipos generan el XML desde plantillas con control total del formato en lugar de depender solo de librerías genéricas.
¿Por qué nunca se debe enviar el comprobante a SUNAT de forma síncrona?
Porque el endpoint de SUNAT puede tardar hasta 30 segundos en responder en horas pico, y a veces no responde. Si lo envías dentro del request del usuario, su pantalla se congela o falla. El patrón correcto es asíncrono: guardar el comprobante como 'pending', responder al usuario al instante, y tener un worker en background que lo envía, actualiza el estado y reintenta los errores transitorios con backoff exponencial.
¿Qué necesito para firmar comprobantes electrónicos?
Un certificado digital vigente de la empresa emisora (cuesta entre 150 y 300 dólares al año), accesible para el servidor que genera los XML. El comprobante se firma con XMLDSig enveloped y algoritmo SHA-256, como exige SUNAT. El certificado (.p12 o .pfx con su clave) nunca debe vivir en el repositorio: va en variables de entorno o un vault. Si el certificado expira y nadie lo renueva, la facturación se detiene por completo.
¿Se puede anular un comprobante ya emitido?
Sí, mediante una baja: se genera un XML de baja que referencia el comprobante original, se firma y se envía a SUNAT, que la procesa en su batch nocturno (no es inmediato). Al día siguiente se consulta el estado. El punto crítico es que una baja no se puede revertir: si anulaste por error, hay que emitir un comprobante nuevo. Por eso conviene validar bien antes de dar de baja.
Compartir artículo