@nextpyme/sdk
v1.0.0
Published
SDK oficial de Nextpyme para facturación electrónica, nómina y documentos DIAN Colombia
Maintainers
Readme
@nextpyme/sdk
SDK oficial de Nextpyme para facturación electrónica, nómina electrónica, documento soporte y más servicios DIAN en Colombia.
Un solo npm install y tienes todo listo: autenticación, reintentos opcionales, manejo de errores, y acceso a todos los endpoints de la API.
Instalación
npm install @nextpyme/sdkCompatible con Node.js >= 18 (usa fetch nativo). Funciona con ESM y CommonJS.
// ESM
import { NextpymeClient } from '@nextpyme/sdk';
// CommonJS
const { NextpymeClient } = require('@nextpyme/sdk');Inicio rápido
import { NextpymeClient } from '@nextpyme/sdk';
const nextpyme = new NextpymeClient({
token: 'tu-bearer-token-aqui', // Obtenlo en https://nextpyme.plus
});
// Consultar datos de la empresa
const empresa = await nextpyme.reports.company();
console.log(empresa);
// Emitir una factura
const factura = await nextpyme.invoice.create({
number: 1,
type_document_id: 1,
customer: { ... },
legal_monetary_totals: { ... },
invoice_lines: [ ... ],
});
console.log(factura);
// { success: true, message: '...', dian: { isValid: true, ... }, cufe: '...', ... }Configuración
const nextpyme = new NextpymeClient({
// Requerido
token: 'eyJhbGciOi...', // Bearer token (mínimo 50 caracteres)
// Opcionales
environment: 'production', // 'production' | 'custom'
debug: false, // true para ver logs en consola
timeoutMs: 30000, // Timeout por petición (ms)
});| Parámetro | Tipo | Default | Descripción |
|---------------|-----------|---------------------|---------------------------------------------------|
| token | string | — | Requerido. Bearer token de autenticación |
| environment | string | 'production' | Ambiente: production o custom |
| baseUrl | string | — | URL base (solo si environment es custom) |
| debug | boolean | false | Habilitar logs de debug en consola |
| timeoutMs | number | 30000 | Timeout por request en milisegundos |
| maxRetries | number | 2 | Máximo de reintentos cuando retry: true |
| userAgent | string | '@nextpyme/sdk' | Header User-Agent personalizado |
Ambientes
| Ambiente | URL base |
|----------------|---------------------------------------|
| production | https://api.nextpyme.plus/api |
| custom | La que definas en baseUrl |
Opciones por petición
Todos los métodos que reciben opts aceptan:
| Opción | Tipo | Default | Descripción |
|-------------|-----------------------------|---------|------------------------------------------|
| retry | boolean | false | Habilitar reintentos (429/5xx/red) |
| timeoutMs | number | 30000 | Timeout para esta petición |
| headers | Record<string, string> | {} | Headers adicionales |
// Sin reintentos (default)
await nextpyme.invoice.create(body);
// Con reintentos habilitados
await nextpyme.invoice.create(body, { retry: true });
// Con timeout extendido
await nextpyme.invoice.create(body, { retry: true, timeoutMs: 60000 });Servicios disponibles
| # | Módulo | Método | HTTP | Endpoint | Descripción |
|----|---------------------|-------------------------------|------|-----------------------------------------------|----------------------------------------------|
| 1 | invoice | create(body, opts?) | POST | /ubl2.1/invoice | Factura electrónica de venta |
| 2 | | creditNote(body, opts?) | POST | /ubl2.1/credit-note | Nota crédito |
| 3 | | debitNote(body, opts?) | POST | /ubl2.1/debit-note | Nota débito |
| 4 | | eqdoc(body, opts?) | POST | /ubl2.1/eqdoc | Factura POS (documento equivalente) |
| 5 | | exportInvoice(body, opts?) | POST | /ubl2.1/invoice-export | Factura de exportación |
| 6 | | contingency(body, opts?) | POST | /ubl2.1/invoice-contingency | Factura en contingencia |
| 7 | | aiu(body, opts?) | POST | /ubl2.1/invoice-aiu | Factura AIU (construcción) |
| 8 | | transport(body, opts?) | POST | /ubl2.1/invoice-transport | Factura de transporte |
| 9 | | mandate(body, opts?) | POST | /ubl2.1/invoice-mandate | Factura de mandato |
| 10 | payroll | create(body, opts?) | POST | /ubl2.1/payroll | Nómina electrónica individual |
| 11 | | adjustNote(body, opts?) | POST | /ubl2.1/payroll-adjust-note | Nota de ajuste de nómina |
| 12 | supportDocument | create(body, opts?) | POST | /ubl2.1/support-document | Documento soporte |
| 13 | | creditNote(body, opts?) | POST | /ubl2.1/sd-credit-note | Nota crédito documento soporte |
| 14 | events | sendWithData(body, opts?) | POST | /ubl2.1/send-event-data | Evento RADIAN con datos |
| 15 | | sendWithXml(body, opts?) | POST | /ubl2.1/send-event | Evento RADIAN con XML adjunto |
| 16 | status | document(uuid) | POST | /ubl2.1/status/document/{uuid} | Estado de documento en DIAN |
| 17 | | events(uuid) | POST | /ubl2.1/status/events-document/{uuid} | Eventos de una factura en DIAN |
| 18 | | documentInfo(uuid) | POST | /ubl2.1/status/document-info/{uuid} | Documento resumen DIAN |
| 19 | reports | software() | GET | /ubl2.1/reports/software | Datos del software en DIAN |
| 20 | | company() | GET | /ubl2.1/config/company | Datos de la empresa |
| 21 | | resolutions(filters?) | GET | /ubl2.1/reports/resolutions | Resoluciones configuradas |
| 22 | | dashboard(body) | POST | /ubl2.1/reports/dashboard | Dashboard de consumos |
| 23 | | masterTables(body) | POST | /ubl2.1/reports/master/database | Tablas maestras (municipios, etc.) |
| 24 | | certificates(nit) | GET | /ubl2.1/certificates-listing/{nit} | Certificados digitales y vencimiento |
| 25 | config | logo(body) | PUT | /ubl2.1/config/logo | Configurar logotipo (base64) |
| 26 | | environment(body) | PUT | /ubl2.1/config/environment | Cambiar ambiente facturación/nómina |
| 27 | | resolution(body) | PUT | /ubl2.1/config/resolution | Configurar resolución de numeración |
| 28 | | changeTemplate(body) | PUT | /ubl2.1/config/change-template | Cambiar plantilla del PDF |
| 29 | downloads | download(nit, filename) | GET | /ubl2.1/download/{nit}/{filename} | Descargar cualquier archivo del documento |
| 30 | | xmlFromDian(uuid) | POST | /ubl2.1/xml/document/{uuid} | Descargar XML directamente desde la DIAN |
| 31 | | joinPdfs(body) | POST | /ubl2.1/join-pdfs | Unir múltiples PDFs en uno |
| 32 | email | send(body) | POST | /ubl2.1/send-email | Reenviar email de un documento |
| 33 | plans | userInfo() | GET | /ubl2.1/plan/infoplanuser | Folios disponibles del usuario |
| 34 | | listPackages() | GET | /ubl2.1/plan/assign-package-user | Paquetes asignados (solo aliados) |
| 35 | | assignPackage(body) | PUT | /ubl2.1/plan/assign-package-user | Asignar paquete (solo aliados) |
| 36 | dian | statusDocument(trackId) | POST | /ubl2.1/status/document/{trackId} | Estado de documento en DIAN por CUFE/UUID |
| 37 | | numberingRange(body) | POST | /ubl2.1/numbering-range | Resoluciones de numeración DIAN |
| 38 | | rutRues(body) | POST | /ubl2.1/rut-rues | Consultar RUT/RUES de un tercero |
| 39 | | invoiceData(body) | GET | /return-invoice-data | Compras recibidas |
Módulos y ejemplos
nextpyme.invoice — Facturación electrónica
// Factura de venta
const factura = await nextpyme.invoice.create(body);
// { success: true, message: '...', dian: { isValid: true, ... }, cufe: '...' }
// Con reintentos
const factura = await nextpyme.invoice.create(body, { retry: true });
// Nota crédito (requiere billing_reference con CUFE de la factura original)
const nc = await nextpyme.invoice.creditNote(body);
// Nota débito
const nd = await nextpyme.invoice.debitNote(body);
// Factura POS (documento equivalente electrónico)
const pos = await nextpyme.invoice.eqdoc(body);
// Variantes especiales — mismo payload base, URL distinta
const exportacion = await nextpyme.invoice.exportInvoice(body);
const contingencia = await nextpyme.invoice.contingency(body);
const construccion = await nextpyme.invoice.aiu(body);
const transporte = await nextpyme.invoice.transport(body);
const mandato = await nextpyme.invoice.mandate(body);nextpyme.payroll — Nómina electrónica
// Emitir nómina individual
const nomina = await nextpyme.payroll.create(body);
// Nota de ajuste (reemplazo o eliminación)
const ajuste = await nextpyme.payroll.adjustNote(body);nextpyme.supportDocument — Documento soporte
// Documento soporte (proveedores no obligados a facturar)
const ds = await nextpyme.supportDocument.create(body);
// Nota crédito de documento soporte
const ncds = await nextpyme.supportDocument.creditNote(body);nextpyme.events — Eventos RADIAN
// Evento con datos (sin XML)
const evento = await nextpyme.events.sendWithData({
event_id: 1,
type_rejection_id: null,
document_reference: { cufe: 'abc123...' },
});
// Evento con XML adjunto
const eventoXml = await nextpyme.events.sendWithXml({
event_id: 1,
base64_attacheddocument_name: 'documento.xml',
base64_attacheddocument: 'PD94bWwg...',
});IDs de eventos RADIAN
| event_id | Código DIAN | Evento |
|:----------:|:-----------:|--------|
| 1 | 030 | Acuse de recibo de Factura Electrónica de Venta |
| 2 | 031 | Reclamo de la Factura Electrónica de Venta |
| 3 | 032 | Recibo del bien y/o prestación del servicio |
| 4 | 033 | Aceptación expresa |
| 5 | 034 | Aceptación tácita |
| 6 | 02 | Documento validado por la DIAN |
| 7 | 04 | Documento rechazado por la DIAN |
nextpyme.status — Consultas de estado DIAN
// Validar estado de un documento
const estado = await nextpyme.status.document('uuid-del-documento');
// Ver eventos de una factura
const eventos = await nextpyme.status.events('uuid-del-documento');
// Documento resumen DIAN
const info = await nextpyme.status.documentInfo('uuid-del-documento');nextpyme.reports — Reportes y consultas
// Datos del software registrado en DIAN
const sw = await nextpyme.reports.software();
// Datos de la empresa
const empresa = await nextpyme.reports.company();
// Resoluciones configuradas (con filtros opcionales)
const todas = await nextpyme.reports.resolutions();
const filtradas = await nextpyme.reports.resolutions({
prefix: 'SETP',
type_document_id: 1,
resolution: '18760000001',
});
// Dashboard de consumos por rango de fechas
const dashboard = await nextpyme.reports.dashboard({
date_between: true,
start_date: '2025-01-01 00:00:00',
end_date: '2025-12-31 23:59:59',
});
// Tablas maestras (municipios, departamentos, etc.)
const tablas = await nextpyme.reports.masterTables({
tables: [{ table: 'municipalities' }, { table: 'departments' }],
});
// Certificados digitales y vencimiento
const certs = await nextpyme.reports.certificates('900123456');nextpyme.config — Configuración de la empresa
// Configurar logotipo (solo JPG, base64 sin prefijo)
await nextpyme.config.logo({ logo: '/9j/4AAQSkZJRg...' });
// Cambiar ambiente de facturas (1=Producción, 2=Pruebas)
await nextpyme.config.environment({ type_environment_id: 2 });
// Cambiar ambiente de factura POS (1=Producción, 2=Pruebas)
await nextpyme.config.environment({ eqdocs_type_environment_id: 2 });
// Cambiar ambiente de nómina (1=Pruebas, 2=Producción)
await nextpyme.config.environment({ payroll_type_environment_id: 2 });
// Configurar resolución de numeración
await nextpyme.config.resolution({
type_document_id: 1,
prefix: 'SETP',
resolution: '18764000001',
resolution_date: '2019-01-19',
technical_key: 'fc8e...',
from: 990000000,
to: 995000000,
date_from: '2019-01-19',
date_to: '2030-01-19',
});
// Cambiar plantilla del PDF ("2", "one", "two", "four")
await nextpyme.config.changeTemplate({ template_name: 'one' });nextpyme.downloads — Descargas de archivos
El nombre del archivo sigue convenciones según su tipo:
| Archivo | Patrón | Ejemplo |
|---------|--------|---------|
| PDF | {DOC_PREFIX}-{prefix}{number}.pdf | FES-SETP990000001.pdf |
| XML Invoice (UBL) | {DOC_PREFIX}-{prefix}{number}.xml | FES-SETP990000001.xml |
| XML AttachedDocument | Attachment-{prefix}{number}.xml | Attachment-SETP990000001.xml |
| ZIP (PDF + Attached) | ZipAttachm-{prefix}{number}.zip | ZipAttachm-SETP990000001.zip |
| Respuesta DIAN SOAP | RptaFE-{prefix}{number}.xml | RptaFE-SETP990000001.xml |
Donde DOC_PREFIX es: FES, NCS, NDS, DSS, POSS, NIS, NAS.
const nit = '900123456';
// Formato nativo (default)
await nextpyme.downloads.download(nit, 'FES-SETP990000001.pdf');
// Contenido en base64
await nextpyme.downloads.download(nit, 'FES-SETP990000001.pdf', { base64: true });
// XML Invoice
await nextpyme.downloads.download(nit, 'FES-SETP990000001.xml');
// XML AttachedDocument
await nextpyme.downloads.download(nit, 'Attachment-SETP990000001.xml');
// ZIP
await nextpyme.downloads.download(nit, 'ZipAttachm-SETP990000001.zip');
// Respuesta DIAN SOAP
await nextpyme.downloads.download(nit, 'RptaFE-SETP990000001.xml');
// XML directamente desde la DIAN por UUID/CUFE
await nextpyme.downloads.xmlFromDian('67cf0488234...');
// Unir múltiples PDFs en uno
const joined = await nextpyme.downloads.joinPdfs({
name_joined_pdfs: 'reporte-mensual',
pdfs: [
{ type_document_id: 1, prefix: 'SETP', number: '990000001' },
{ type_document_id: 1, prefix: 'SETP', number: '990000002' },
],
});nextpyme.email — Envío de emails
await nextpyme.email.send({
prefix: 'SETP',
number: '990000001',
alternate_email: '[email protected]',
showacceptrejectbuttons: true,
email_cc_list: [{ email: '[email protected]' }],
send_email_cc_list_as_email_cc: true,
});nextpyme.plans — Planes y recargas
// Consultar folios disponibles
const info = await nextpyme.plans.userInfo();
// Ver paquetes asignados (solo aliados)
const paquetes = await nextpyme.plans.listPackages();
// Asignar paquete de documentos (solo aliados)
await nextpyme.plans.assignPackage({
user_identification_number: 900123456,
absolut_start_plan_date: '2025-01-01',
absolut_documents: 1000,
});nextpyme.dian — Consultas directas DIAN
// Consultar estado de un documento en DIAN por CUFE/UUID
const estado = await nextpyme.dian.statusDocument('002515775b03ae7674b470788f07...');
// {
// success: true,
// message: 'Consulta generada con éxito',
// dian: {
// isValid: true,
// statusCode: '00',
// statusDescription: 'Procesado Correctamente.',
// statusMessage: 'La Factura electrónica FE212, ha sido autorizada.',
// errorMessage: [],
// },
// cufecude: '002515775b03ae7674b470...',
// ...
// }
// Consultar resoluciones de numeración en DIAN
const rangos = await nextpyme.dian.numberingRange({
IDSoftware: 'tu-id-software',
});
// {
// success: true,
// message: 'Acción completada OK.',
// resolutions: [
// {
// prefix: 'SETP',
// resolution: '18764000001',
// resolution_date: '2021-08-25',
// technical_key: 'fc8e...',
// from: 990000000,
// to: 995000000,
// date_from: '2019-01-19',
// date_to: '2030-01-19',
// },
// ],
// }
// Usar la resolución directamente en config:
const { resolutions } = await nextpyme.dian.numberingRange({ IDSoftware: '...' });
if (resolutions.length > 0) {
await nextpyme.config.resolution({
type_document_id: 1,
...resolutions[0],
});
}
// Consultar RUT/RUES de un tercero
const rut = await nextpyme.dian.rutRues({
identification_number: 900123456,
type_document_identification_id: 3, // 1=CC, 2=CE, 3=NIT, etc.
rues: true,
});
// Ver compras recibidas
const compras = await nextpyme.dian.invoiceData();Formato de respuestas
Módulos de emisión (invoice, payroll, supportDocument, events)
Devuelven la respuesta de la API con el campo dian normalizado:
{
"success": true,
"message": "Factura generada exitosamente.",
"dian": {
"isValid": true,
"statusCode": "00",
"statusDescription": "Procesado Correctamente.",
"statusMessage": "La Factura electrónica FE001, ha sido autorizada.",
"errorMessage": []
},
"cufe": "abc123...",
"urlinvoicepdf": "FES-SETP990000001.pdf",
"urlinvoicexml": "FES-SETP990000001.xml"
}Módulo reports (respuesta formateada)
{
ok: true, // Booleano basado en success de la API
message: '...',
data: { ... }, // Datos extraídos automáticamente
raw: { ... }, // Respuesta cruda completa
}Módulo dian.numberingRange() (respuesta normalizada)
{
success: true,
message: '...',
resolutions: [ ... ], // Siempre array (vacío si no hay datos)
raw: { ... },
}Manejo de errores
import { NextpymeClient, NextpymeError, AuthError, ValidationError, ServerError } from '@nextpyme/sdk';
try {
const factura = await nextpyme.invoice.create(body);
} catch (err) {
if (err instanceof ValidationError) {
// 422 — Campos inválidos
console.log(err.code); // 'VALIDATION_FAILED'
console.log(err.status); // 422
console.log(err.details); // { success: false, errors: { campo: ['...'] } }
}
if (err instanceof AuthError) {
// 401/403 — Token inválido o expirado
console.log(err.code); // 'AUTH_INVALID'
}
if (err instanceof ServerError) {
// 500-504 — Error del servidor
console.log(err.code); // 'SERVER_ERROR'
}
if (err instanceof NextpymeError) {
// Cualquier error del SDK
console.log(err.toJSON());
}
}Códigos de error
| Código | Clase | HTTP | Descripción |
|---------------------|-------------------|---------|-----------------------------------------|
| AUTH_INVALID | AuthError | 401/403 | Token inválido, expirado o sin permisos |
| VALIDATION_FAILED | ValidationError | 422 | Campos requeridos o datos inválidos |
| SERVER_ERROR | ServerError | 500-504 | Error interno del servidor |
| HTTP_ERROR | NextpymeError | Otros | Cualquier otro error HTTP |
| TIMEOUT | NextpymeError | — | La petición excedió el timeout |
| NETWORK_ERROR | NextpymeError | — | Sin conexión o DNS no resuelto |
Estructura uniforme (toJSON())
app.post('/factura', async (req, res) => {
try {
const result = await nextpyme.invoice.create(req.body);
res.json(result);
} catch (err) {
res.status(err.status || 500).json(err); // toJSON() se aplica automáticamente
}
});{
"success": false,
"message": "Error de validación.",
"code": "VALIDATION_FAILED",
"status": 422,
"method": "POST",
"path": "/ubl2.1/invoice",
"errors": { "campo": ["El campo es requerido."] }
}Reintentos
Los reintentos están desactivados por defecto. Se habilitan por petición con { retry: true }:
// Sin reintentos (default)
await nextpyme.invoice.create(body);
// Con reintentos
await nextpyme.invoice.create(body, { retry: true });| Se reintenta | No se reintenta | |---------------------------|---------------------------| | HTTP 429 (rate limiting) | HTTP 401/403 (auth) | | HTTP 500-504 (servidor) | HTTP 422 (validación) | | Errores de red | HTTP 404 (no encontrado) |
Espera entre reintentos (backoff exponencial): 500ms → 1s → 2s → 4s...
El máximo de reintentos se configura globalmente con maxRetries (default: 2).
Modo debug
const nextpyme = new NextpymeClient({
token: '...',
debug: true,
});[NEXTPYME SDK] POST /ubl2.1/invoice → request { body: { ... } }
[NEXTPYME SDK] POST /ubl2.1/invoice ← 200 (432ms)Middlewares personalizados
nextpyme.http.useMiddleware(async (ctx, next) => {
ctx.headers['X-Custom-Header'] = 'valor';
const response = await next();
console.log(`Response status: ${response.status}`);
return response;
});Plugins
const miPlugin = {
name: 'mi-plugin',
setup({ client, http }) {
http.useMiddleware(async (ctx, next) => {
return next();
});
client.miModulo = {
async miMetodo() {
const res = await http.get('/mi-endpoint');
return res.json;
},
};
},
};
const nextpyme = new NextpymeClient({ token: '...' });
nextpyme.use(miPlugin);Ejemplo completo: Express + SDK
import express from 'express';
import { NextpymeClient, ValidationError, AuthError } from '@nextpyme/sdk';
const app = express();
app.use(express.json());
const nextpyme = new NextpymeClient({
token: process.env.NEXTPYME_TOKEN,
environment: 'production',
});
// Emitir factura
app.post('/api/facturas', async (req, res) => {
try {
const result = await nextpyme.invoice.create(req.body);
res.json(result);
} catch (err) {
if (err instanceof ValidationError) {
return res.status(422).json(err);
}
if (err instanceof AuthError) {
return res.status(401).json(err);
}
res.status(500).json({ success: false, message: err.message });
}
});
// Consultar estado
app.get('/api/facturas/:uuid/estado', async (req, res) => {
try {
const estado = await nextpyme.status.document(req.params.uuid);
res.json(estado);
} catch (err) {
res.status(err.status || 500).json(err);
}
});
app.listen(3000);Licencia
MIT
