Factuplan SDK
Librería oficial de JavaScript y TypeScript para crear facturas electrónicas autorizadas por el SRI de Ecuador. Zero dependencies.
Instalación
npm install @factuplan/sdkpnpm add @factuplan/sdkyarn add @factuplan/sdkAutenticación
Crea una API key desde Configuración → Claves de API en tu cuenta de Factuplan.
import { Factuplan } from '@factuplan/sdk';
const factuplan = new Factuplan('ak_dev_tu_api_key_aqui');
// Con opciones personalizadas
const factuplan = new Factuplan('ak_dev_...', {
baseUrl: 'https://api.factuplan.com/api/v1',
timeout: 30000,
});Nunca expongas tu API key en el frontend. Úsala solo desde tu servidor backend.
Clientes
Crear
const cliente = await factuplan.customers.create({
identificationType: 'RUC', // RUC | CEDULA | PASSPORT | FINAL_CONSUMER
identification: '0993378150001',
legalName: 'Empresa Demo S.A.',
email: '[email protected]', // opcional
address: 'Guayaquil, Ecuador', // opcional
phone: '0991234567', // opcional
});Listar
const { data: clientes, meta } = await factuplan.customers.list({
page: 1,
limit: 20,
search: 'empresa',
});
console.log(meta.total, 'clientes encontrados');Obtener / Actualizar / Eliminar
const cliente = await factuplan.customers.get('id');
await factuplan.customers.update('id', { email: '[email protected]' });
await factuplan.customers.delete('id');Productos
Crear
const producto = await factuplan.products.create({
code: 'SERV-001',
name: 'Servicio de consultoría',
unitPrice: 150.00,
type: 'SERVICE', // PRODUCT | SERVICE
taxType: 'IVA_RATE', // IVA_0 | IVA_RATE | NOT_TAXABLE | EXEMPT
description: 'Hora de consultoría técnica',
});Listar / Actualizar / Eliminar
const { data: productos } = await factuplan.products.list({ search: 'consultoría' });
await factuplan.products.update('id', { unitPrice: 175.00 });
await factuplan.products.delete('id');Facturas
Crear factura
Crea una factura electrónica completa. El sistema genera el XML, lo firma, lo envía al SRI, genera el PDF y envía el email.
const factura = await factuplan.invoices.create({
// Punto de emisión: elige UNA de estas 3 opciones
// Opción 1: por UUID
emissionPointId: 'ep_id',
// Opción 2: por códigos SRI
// establishment: '001',
// emissionPoint: '001',
// Opción 3: omitir todo (auto-detecta si solo hay un punto de emisión activo)
customer: {
identificationType: 'RUC',
identification: '0993378150001',
legalName: 'Cliente S.A.',
email: '[email protected]',
saveToContacts: true,
},
items: [
{
code: 'SERV-001',
description: 'Servicio de consultoría',
quantity: 10,
unitPrice: 150.00,
discount: 0,
taxType: 'IVA_RATE', // IVA_0 | IVA_RATE | NOT_TAXABLE | EXEMPT
tax: 15, // Tarifa IVA: 0, 5, 8, 12, 14, 15 (default: 15)
},
],
paymentMethod: '20',
additionalInfo: { 'Vendedor': 'Juan Pérez' },
});
console.log(factura.id); // ID del comprobante
console.log(factura.accessKey); // Clave de acceso (49 dígitos)
console.log(factura.sequential); // Número secuencialPunto de emisión
El punto de emisión se puede resolver de tres formas. Si no se envía ningún parámetro, el sistema auto-detecta el único punto de emisión activo del contribuyente.
// Usar códigos SRI del establecimiento y punto de emisión
const factura = await factuplan.invoices.create({
establishment: '001',
emissionPoint: '001',
customer: { ... },
items: [ ... ],
});// Si solo tienes un punto de emisión activo, no necesitas enviarlo
const factura = await factuplan.invoices.create({
customer: { ... },
items: [ ... ],
});Tarifas de IVA
El campo tax permite especificar la tarifa de IVA cuando usas taxType: 'IVA_RATE'. Si no se envía, se aplica 15% por defecto.
| tax | Código SRI | Descripción |
|---|---|---|
| 0 | 0 | IVA 0% |
| 5 | 5 | IVA 5% |
| 8 | 8 | IVA 8% |
| 12 | 2 | IVA 12% |
| 14 | 3 | IVA 14% |
| 15 | 4 | IVA 15% (default) |
items: [
{
code: 'PROD-001',
description: 'Producto con IVA reducido',
quantity: 1,
unitPrice: 100.00,
taxType: 'IVA_RATE',
tax: 5, // IVA 5% en lugar del 15% por defecto
},
]Formas de pago
El campo paymentMethod indica la forma de pago según el catálogo del SRI. Si no se envía, se aplica '01' por defecto.
| Código | Descripción |
|---|---|
| 01 | Sin utilización del sistema financiero |
| 15 | Compensación de deudas |
| 16 | Tarjeta de débito |
| 17 | Dinero electrónico |
| 18 | Tarjeta prepago |
| 19 | Tarjeta de crédito |
| 20 | Otros con utilización del sistema financiero |
| 21 | Endoso de títulos |
Consultar estado
const estado = await factuplan.invoices.getStatus('factura_id');
// estado.status: PROCESSING | AUTHORIZED | COMPLETED | ERROR | REJECTED
if (estado.status === 'COMPLETED') {
console.log(estado.authorizationNumber);
}Descargar XML y PDF
URLs pre-firmadas que expiran en 5 minutos.
const { url: xmlUrl } = await factuplan.invoices.downloadXml('id');
const { url: pdfUrl } = await factuplan.invoices.downloadPdf('id');Ejemplo completo
import { Factuplan } from '@factuplan/sdk';
const factuplan = new Factuplan(process.env.FACTUPLAN_API_KEY!);
async function crearFactura() {
// 1. Buscar o crear cliente
const { data: clientes } = await factuplan.customers.list({
search: '0993378150001',
});
let cliente = clientes[0] ?? await factuplan.customers.create({
identificationType: 'RUC',
identification: '0993378150001',
legalName: 'Mi Cliente S.A.',
email: '[email protected]',
});
// 2. Crear factura (sin emissionPointId → auto-detecta)
const factura = await factuplan.invoices.create({
customer: {
identificationType: cliente.identificationType,
identification: cliente.identification,
legalName: cliente.legalName,
email: cliente.email,
},
items: [
{
code: 'PROD-001',
description: 'Laptop Dell XPS 15',
quantity: 1,
unitPrice: 1500.00,
taxType: 'IVA_RATE',
tax: 15,
},
],
paymentMethod: '19',
});
// 3. Esperar autorización
let estado;
do {
await new Promise((r) => setTimeout(r, 3000));
estado = await factuplan.invoices.getStatus(factura.id);
} while (!['COMPLETED', 'ERROR', 'REJECTED'].includes(estado.status));
if (estado.status === 'COMPLETED') {
const { url } = await factuplan.invoices.downloadPdf(factura.id);
console.log('PDF:', url);
}
}
crearFactura();Manejo de errores
import { FactuplanError, AuthenticationError } from '@factuplan/sdk';
try {
await factuplan.invoices.create({ ... });
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('API key inválida');
} else if (error instanceof FactuplanError) {
console.error(error.code); // "INVOICE_4002"
console.error(error.message); // Descripción
console.error(error.statusCode); // 422
console.error(error.details); // Detalles adicionales
}
}Códigos de error
| Código | HTTP | Descripción |
|---|---|---|
| AUTH_ERROR | 401 | API key inválida o expirada |
| RATE_LIMIT | 429 | Límite de solicitudes excedido |
| API_10001 | 403 | Plan no compatible con la operación |
| API_10002 | 429 | Cuota mensual excedida |
| INVOICE_4002 | 422 | Datos del cliente inválidos |
| INVOICE_4003 | 422 | Detalle de factura vacío |
| CERT_3008 | 422 | Certificado expirado |
| CUSTOMER_7004 | 409 | Cliente duplicado |
| PRODUCT_6002 | 409 | Código de producto duplicado |