¿Sigues emitiendo facturas manualmente? Si eres desarrollador en Perú, probablemente has sufrido con los procesos manuales de facturación de SUNAT. ¡Hay una mejor manera! Te muestro cómo automatizar todo el proceso con menos de 50 líneas de código.
📋 Lo que vas a aprender
- ✅ Configurar facturación electrónica desde código
- ✅ Integrar SUNAT con Node.js usando APIs modernas
- ✅ Manejar errores y validaciones como un pro
- ✅ Optimizar el flujo para aplicaciones en producción
- ✅ Casos de uso reales y mejores prácticas
Tiempo estimado: 10-15 minutos | Nivel: Intermedio
🎯 El problema que todos enfrentamos
Como desarrolladores, constantemente necesitamos integrar sistemas de facturación en nuestras aplicaciones. El proceso tradicional implica:
- 😤 Llenar formularios web manualmente
- ⏰ Perder tiempo en tareas repetitivas
- 🐛 Errores humanos en la captura de datos
- 🔄 Falta de automatización en workflows
La solución: Una API que maneje todo esto por nosotros.
🛠️ Tecnologías que usaremos
// Stack técnico
const stack = {
runtime: "Node.js 18+",
API: "Billme",
method: "REST API",
format: "JSON",
auth: "Token-based"
};
🚀 Setup inicial (2 minutos)
Prerrequisitos
- Node.js 18 o superior
- Cuenta gratuita en Billme
- RUC de prueba
1. Crear cuenta de testing
# Paso 1: Registrarse en Billme
# Paso 2: Crear empresa de prueba
# Paso 3: Obtener token de sandbox
💡 Pro tip: Billme tiene ambiente de pruebas gratuito, perfecto para desarrollo y testing.
Sigue su documentación oficial para el setup inicial.
💻 Implementación paso a paso
Estructura del proyecto
facturacion-sunat/
├── src/
│ ├── config/
│ │ └── billme.js
│ ├── services/
│ │ └── invoiceService.js
│ ├── utils/
│ │ └── validator.js
│ └── script.js
└── package.json
1. Configuración base
// config/billme.js
const config = {
baseURL: 'https://www.api.billmeperu.com/api/v1',
endpoints: {
invoice: '/Emission/EnviarBoletaFactura'
},
token: process.env.BILLME_TOKEN || 'your-token-here'
};
export default config;
2. Servicio de facturación (¡La magia sucede aquí!)
// services/invoiceService.js
import config from '../config/billme.js';
class InvoiceService {
constructor() {
this.baseURL = config.baseURL;
this.token = config.token;
}
/**
* Emite una factura electrónica a SUNAT
* @param {Object} invoiceData - Datos de la factura
* @returns {Promise<Object>} Respuesta de SUNAT
*/
async emitInvoice(invoiceData) {
const url = `${this.baseURL}${config.endpoints.invoice}`;
try {
console.log('🚀 Emitiendo factura a SUNAT...');
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'token': this.token,
'Accept': 'application/json'
},
body: JSON.stringify(invoiceData)
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Error ${response.status}: ${errorData.message || 'Error desconocido'}`);
}
const result = await response.json();
console.log('✅ Factura emitida exitosamente');
console.log(`📄 Serie: ${invoiceData.serie}-${invoiceData.correlativo}`);
console.log(`💰 Monto: S/ ${invoiceData.totales.totalPagar}`);
return result;
} catch (error) {
console.error('❌ Error al emitir factura:', error.message);
throw error;
}
}
/**
* Genera datos de factura de ejemplo
* @returns {Object} Estructura de factura válida
*/
generateSampleInvoice() {
return {
tipoOperacion: "010",
serie: "F001",
correlativo: this.generateCorrelativo(),
fechaEmision: new Date().toISOString().split('T')[0],
horaEmision: "00:00:00",
fechaVencimiento: new Date().toISOString().split('T')[0],
codigoTipoOperacion: "0101",
codigoTipoDocumento: "01",
moneda: "PEN",
montoCredito: 0,
formaPago: "Contado",
igv: 18.00,
icbper: 0,
cuotas: [],
// Datos del emisor (tu empresa)
emisor: {
codigoTipoDocumento: "6",
numDocumento: "20123456721",
razonSocial: "TU EMPRESA SAC",
nombreComercial: "TU EMPRESA",
ubigeo: "150101", // Lima
ciudad: "LIMA",
distrito: "LIMA",
provincia: "LIMA",
direccion: "AV. EJEMPLO 123, LIMA"
},
// Datos del cliente
cliente: {
codigoTipoDocumento: "1", // DNI
numDocumento: "12345678",
razonSocial: "CLIENTE EJEMPLO",
nombreComercial: "CLIENTE EJEMPLO",
ubigeo: "",
ciudad: "",
distrito: "",
provincia: "",
direccion: ""
},
// Cálculos automáticos
totales: {
totalOpGravadas: 100.00,
totalOpInafectas: 0,
totalOpExoneradas: 0,
totalImpuestos: 18.00,
totalSinImpuestos: 100.00,
totalConImpuestos: 118.00,
totalPagar: 118.00,
totalDescuentoGlobal: 0,
totalDescuentoProductos: 0
},
// Productos/servicios
productos: [{
unidades: 1,
codigoUnidad: "NIU", // Unidad
nombre: "Desarrollo de Software",
moneda: "PEN",
precioUnitario: 100.00,
precioLista: "118.00",
montoSinImpuesto: 100.00,
montoImpuestos: 18.00,
montoTotal: 100.00,
montoIcbper: 0,
factorIcbper: 0,
montoDescuento: 0,
codigoTipoPrecio: "01",
impuestos: [{
monto: 18.00,
idCategoria: "S",
porcentaje: 18,
codigoAfectacionIgv: "10",
codigoInterTributo: "VAT",
nombreTributo: "IGV",
codigoTributo: "1000"
}],
id: "DEV001",
codigoClasificacion: "531117"
}]
};
}
/**
* Genera correlativo único
* @returns {string} Correlativo con formato
*/
generateCorrelativo() {
const timestamp = Date.now().toString().slice(-5);
return timestamp.padStart(8, '0');
}
}
export default InvoiceService;
3. Script principal con manejo robusto de errores
// script.js
import InvoiceService from './services/invoiceService.js';
class InvoiceApp {
constructor() {
this.invoiceService = new InvoiceService();
}
async run() {
console.log('🏁 Iniciando proceso de facturación electrónica...\n');
try {
// Generar factura de ejemplo
const invoiceData = this.invoiceService.generateSampleInvoice();
console.log('📋 Datos de la factura:');
console.log(` Serie: ${invoiceData.serie}-${invoiceData.correlativo}`);
console.log(` Cliente: ${invoiceData.cliente.razonSocial}`);
console.log(` Monto: S/ ${invoiceData.totales.totalPagar}\n`);
// Emitir factura
const result = await this.invoiceService.emitInvoice(invoiceData);
// Mostrar resultado
this.displayResult(result);
} catch (error) {
this.handleError(error);
}
}
/**
* Muestra el resultado de la emisión
* @param {Object} result - Respuesta de la API
*/
displayResult(result) {
console.log('\n🎉 ¡FACTURA EMITIDA EXITOSAMENTE!');
console.log('═'.repeat(50));
console.log(`📋 Número: ${result.numeroFactura || 'N/A'}`);
console.log(`📅 Fecha: ${result.fechaEmision || 'N/A'}`);
console.log(`🔗 Link PDF: ${result.linkPdf || 'Generando...'}`);
console.log(`✅ Estado: ${result.estado || 'Procesado'}`);
console.log('═'.repeat(50));
}
/**
* Maneja errores de manera elegante
* @param {Error} error - Error ocurrido
*/
handleError(error) {
console.log('\n❌ ERROR EN LA EMISIÓN');
console.log('═'.repeat(50));
console.log(`💥 Mensaje: ${error.message}`);
// Errores comunes y soluciones
if (error.message.includes('token')) {
console.log('💡 Solución: Verifica tu token de Billme');
} else if (error.message.includes('400')) {
console.log('💡 Solución: Revisa los datos de la factura');
} else if (error.message.includes('network') || error.message.includes('fetch')) {
console.log('💡 Solución: Revisa tu conexión a internet');
}
console.log('═'.repeat(50));
}
}
// 🚀 Ejecutar la aplicación
const app = new InvoiceApp();
app.run();
🎯 Ejecutar el código
# Instalar dependencias (si usas package.json)
npm install
# Ejecutar el script
node script.js
Resultado esperado:
🏁 Iniciando proceso de facturación electrónica...
📋 Datos de la factura:
Serie: F001-00012345
Cliente: CLIENTE EJEMPLO
Monto: S/ 118.00
🚀 Emitiendo factura a SUNAT...
✅ Factura emitida exitosamente
📄 Serie: F001-00012345
💰 Monto: S/ 118.00
🎉 ¡FACTURA EMITIDA EXITOSAMENTE!
══════════════════════════════════════════════════
📋 Número: F001-00012345
📅 Fecha: 2025-06-23
✅ Estado: Aceptado por SUNAT
══════════════════════════════════════════════════
🔥 Casos de uso avanzados
1. Facturación masiva
// Procesar múltiples facturas
const invoices = [
{ cliente: 'Cliente A', monto: 100 },
{ cliente: 'Cliente B', monto: 250 },
{ cliente: 'Cliente C', monto: 500 }
];
for (const invoice of invoices) {
await processInvoice(invoice);
await new Promise(resolve => setTimeout(resolve, 1000)); // Rate limiting
}
2. Integración con base de datos
// Ejemplo con MongoDB
const pendingInvoices = await Invoice.find({ status: 'pending' });
for (const invoice of pendingInvoices) {
try {
const result = await invoiceService.emitInvoice(invoice.data);
await Invoice.updateOne(
{ _id: invoice._id },
{ status: 'emitted', sunatResponse: result }
);
} catch (error) {
await Invoice.updateOne(
{ _id: invoice._id },
{ status: 'error', error: error.message }
);
}
}
3. Webhook para notificaciones
// Notificar cuando se emita una factura
app.post('/webhook/invoice-emitted', (req, res) => {
const { invoiceId, status, pdfUrl } = req.body;
// Enviar email al cliente
sendEmailToClient(invoiceId, pdfUrl);
// Actualizar sistema interno
updateInvoiceStatus(invoiceId, status);
res.json({ received: true });
});
⚡ Optimizaciones para producción
1. Variables de entorno
# .env
BILLME_TOKEN=your-production-token
BILLME_ENV=production
MAX_RETRIES=3
RATE_LIMIT_MS=1000
2. Rate limiting y reintentos
class RobustInvoiceService extends InvoiceService {
async emitInvoiceWithRetry(invoiceData, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await this.emitInvoice(invoiceData);
} catch (error) {
if (attempt === maxRetries) throw error;
console.log(`⚠️ Intento ${attempt} falló, reintentando...`);
await this.delay(1000 * attempt); // Backoff exponencial
}
}
}
delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
🎯 Próximos pasos
Una vez que domines lo básico, puedes expandir tu sistema:
- 📧 Envío automático de facturas por email
- 📊 Dashboard de reportes y analytics
- 🔄 Sincronización con sistemas contables
- 📱 API REST para tu frontend
- 🤖 Chatbot para consulta de facturas
🤝 Conclusión
¡Felicidades! Acabas de automatizar uno de los procesos más tediosos para cualquier developer peruano. Con este setup puedes:
✅ Emitir facturas desde cualquier aplicación
✅ Integrar con tus sistemas existentes
✅ Escalar sin límites (casi)
✅ Olvidarte de procesos manuales
¿Qué sigue? Te reto a integrar esto en tu próximo project. Las posibilidades son infinitas.
💬 ¿Te funcionó?
Si implementaste este tutorial:
- 👍 Dale like si te sirvió
- 💬 Comparte tu experiencia en los comentarios
- 🔄 Compártelo con otros devs que necesiten esto
- 🐙 Sube tu versión a GitHub y comparte el repo
¿Tienes dudas? Comenta abajo y te ayudo a resolverlas.
📚 Referencias útiles
Tags: #nodejs #javascript #sunat #facturacion #api #peru #automation #fintech
Top comments (0)