npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@facturalo-pe/node

v1.2.0

Published

SDK oficial de Facturalo para Node.js: emite facturas, boletas, notas y guías de remisión ante SUNAT, consulta RUC/DNI, idempotencia y verifica webhooks.

Readme

@facturalo-pe/node

SDK oficial de Facturalo para Node.js. Emite facturas, boletas, notas de crédito y débito y guías de remisión ante SUNAT, consulta RUC y DNI, trabaja el SIRE y verifica los webhooks.

Documentación completa de la API: docs.facturalo.pe.

npm install @facturalo-pe/node

Node 18 o superior. Solo para el servidor: usa tu token secreto, nunca lo importes en el navegador.

Primera factura

Crea tu empresa en console.facturalo.pe y copia su token Demo (sk_test_...) desde el menú de la empresa, opción Tokens. El token decide el entorno: sk_test_... va a SUNAT beta y sk_live_... a producción.

import { FacturaloClient } from "@facturalo-pe/node";

const facturalo = new FacturaloClient({ token: process.env.FACTURALO_TOKEN! });

const envio = await facturalo.documentos.enviar({
  sunatTransaccion: "0101",
  tipoComprobante: "01",
  serie: "F001",
  correlativo: "1",
  fechaEmision: "2026-10-30",
  moneda: "PEN",
  formaPago: "CONTADO",
  cliente: {
    tipoDocumento: "6",
    numeroDocumento: "20000000001",
    denominacion: "EMPRESA S.A.C.",
    direccion: "AV. LIMA 123 - LIMA",
  },
  items: [
    // precioUnitario incluye IGV; Facturalo calcula el IGV y los totales.
    { unidadMedida: "NIU", descripcion: "SERVICIO DE CONSULTORÍA", cantidad: 1, precioUnitario: 118, tipoIgv: "10" },
  ],
});

if (envio.estado === "ACEPTADA") {
  console.log(envio.enlaces.pdf, envio.cadenaQr);
} else {
  console.log(envio.estado, envio.sunat?.codigo, envio.sunat?.mensaje);
}

Un rechazo de SUNAT no lanza excepción: llega con estado: "RECHAZADA" y el motivo en sunat. Las excepciones son para errores de la petición (validación, token, red).

La respuesta solo identifica el comprobante. El detalle completo (cliente, totales, ítems) se obtiene con documentos.consultar(id).

Sin esperar a SUNAT

const envio = await facturalo.documentos.enviar(documento, {
  webhook: true,
  idempotencyKey: "orden-1042", // evita duplicar si reintentas el POST
});
// envio.estado === "EN_PROCESO": el resultado llega a tu webhook como documento.sunat.respuesta

Recursos

// Documentos (factura, boleta, notas)
await facturalo.documentos.enviar(documento, { webhook, establecimiento });
await facturalo.documentos.generarXml(documento);            // firma el XML sin enviarlo
await facturalo.documentos.consultar(id);                    // detalle completo + estado
await facturalo.documentos.buscar({ tipoComprobante: "01", serie: "F001", correlativo: "1" });
await facturalo.documentos.listar({ fechaInicio: "2026-10-01", estado: "ACEPTADA", pagina: 1 });
await facturalo.documentos.anular({ tipoComprobante: "01", serie: "F001", correlativo: "1", motivo: "Error en el monto" });
await facturalo.documentos.reenviar(id);
await facturalo.documentos.eventos(id);
await facturalo.documentos.eliminar(id);                     // solo NO_ENVIADA
const pdf = await facturalo.documentos.descargar(id, "pdf"); // devuelve un Buffer; también "ticket", "xml" o "cdr"

// Guías de remisión (serie T... remitente, V... transportista)
await facturalo.guias.enviar(guia, { webhook });
await facturalo.guias.consultar(id);
await facturalo.guias.consultarTicket(ticket);
await facturalo.guias.listar({ pagina: 1 });

// Consultas
await facturalo.consultas.ruc("20601476551");
await facturalo.consultas.dni("12345678");
await facturalo.consultas.tipoCambio("2026-10-30");

// Webhooks enviados
await facturalo.webhooks.listar({ estado: "error" });
await facturalo.webhooks.reenviar(eventoId);
// Si tu endpoint no responde 2xx, Facturalo reintenta el webhook hasta 5 veces.

// SIRE (periodo YYYYMM)
await facturalo.sire.ventas.resumen("202610");
await facturalo.sire.compras.comprobantes("202610", { page: 1, perPage: 100 });

Recibir webhooks

Facturalo firma cada webhook con HMAC-SHA256(secret, cuerpo) en el header X-Facturalo-Firma. Verifica siempre con el cuerpo crudo:

import express from "express";
import { construirEventoWebhook, FacturaloSignatureVerificationError } from "@facturalo-pe/node";

app.post("/webhooks/facturalo", express.raw({ type: "application/json" }), (req, res) => {
  try {
    const evento = construirEventoWebhook(req.body, req.header("X-Facturalo-Firma"), process.env.FACTURALO_WEBHOOK_SECRET!);
    if (evento.evento === "documento.sunat.respuesta") {
      // evento.documento.id, evento.sunat.estado, evento.enlaces.pdf...
    }
    res.sendStatus(200);
  } catch (err) {
    if (err instanceof FacturaloSignatureVerificationError) return res.sendStatus(401);
    throw err;
  }
});

El secreto (whsec_...) está en la consola, el menú de la empresa, opción Webhooks, y es distinto en Demo y Live.

Cuenta: empresas y establecimientos

Con el token de usuario (user_sk_...) puedes dar de alta empresas desde tu propio software:

import { FacturaloCuentaClient } from "@facturalo-pe/node";

const cuenta = new FacturaloCuentaClient({ token: process.env.FACTURALO_USER_TOKEN! });
const empresa = await cuenta.empresas.crear({ ruc, nombre, direccion, departamento, provincia, distrito, codigoPostal, sunat: { solUsuario, solClave } });
await cuenta.empresas.actualizarWebhook(empresa.id, { demo: "https://mi-sistema.pe/webhooks/facturalo" });
await cuenta.establecimientos.crear(empresa.id, { nombre, direccion, departamento, provincia, distrito, codigoPostal });

Errores

| Excepción | Cuándo | |---|---| | FacturaloValidationError | 400 / 422. err.errors trae los errores por campo | | FacturaloAuthenticationError | 401: token inválido o regenerado | | FacturaloNotFoundError | 404: no existe en este entorno | | FacturaloRateLimitError | 429 | | FacturaloConnectionError | Red o timeout (default 90 s) | | FacturaloApiError | Clase base de las anteriores, con status y body |

Las consultas (GET) se reintentan solas ante 429/5xx y fallos de red. Los envíos nunca se reintentan automáticamente, para no emitir dos veces el mismo comprobante.

Licencia

MIT © Consultia Digital S.A.C. (Facturalo)