Factuplan SDK
v0.1.0

Factuplan SDK

Librería oficial de JavaScript y TypeScript para crear facturas electrónicas autorizadas por el SRI de Ecuador. Zero dependencies.

Node.js 18+TypeScriptESM & CJSSin dependencias

Instalación

npm
npm install @factuplan/sdk
pnpm
pnpm add @factuplan/sdk
yarn
yarn add @factuplan/sdk

Autenticación

Crea una API key desde Configuración → Claves de API en tu cuenta de Factuplan.

Inicializar el cliente
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 secuencial

Punto 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.

Por códigos SRI
// Usar códigos SRI del establecimiento y punto de emisión
const factura = await factuplan.invoices.create({
  establishment: '001',
  emissionPoint: '001',
  customer: { ... },
  items: [ ... ],
});
Auto-detección
// 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.

taxCódigo SRIDescripción
00IVA 0%
55IVA 5%
88IVA 8%
122IVA 12%
143IVA 14%
154IVA 15% (default)
Ejemplo con IVA 5%
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ódigoDescripción
01Sin utilización del sistema financiero
15Compensación de deudas
16Tarjeta de débito
17Dinero electrónico
18Tarjeta prepago
19Tarjeta de crédito
20Otros con utilización del sistema financiero
21Endoso 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

ejemplo-factura.ts
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ódigoHTTPDescripción
AUTH_ERROR401API key inválida o expirada
RATE_LIMIT429Límite de solicitudes excedido
API_10001403Plan no compatible con la operación
API_10002429Cuota mensual excedida
INVOICE_4002422Datos del cliente inválidos
INVOICE_4003422Detalle de factura vacío
CERT_3008422Certificado expirado
CUSTOMER_7004409Cliente duplicado
PRODUCT_6002409Código de producto duplicado