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

@wepos/sdk

v1.4.1

Published

SDK oficial de WePOS para integradores — facturación electrónica Hacienda CR v4.4. Emite FE/TE/NC/ND/FEE, consulta catálogo, clientes e inventario.

Downloads

889

Readme

@wepos/sdk

SDK oficial de WePOS — facturación electrónica Hacienda Costa Rica v4.4 para integradores.

npm version downloads node types license: MIT

TypeScript/Node · cero dependencias en runtime · ESM + CJS · tipos incluidos


Tabla de contenido

¿Qué resuelve?

Conecta cualquier sistema de terceros (ecommerce, ERP, app a medida, backend) con WePOS para emitir comprobantes electrónicos ante Hacienda Costa Rica y consultar catálogo, clientes e inventario — sin lidiar con XML, firmas digitales, claves numéricas ni el ciclo asíncrono de Hacienda. Tú llamas un método tipado; el SDK se encarga del resto.

const invoice = await wepos.invoices.issueAndWait({
  documentType: 'FE',
  customer: { idType: 'CEDULA_JURIDICA', idNumber: '3101123456', name: 'Cliente S.A.' },
  lines: [{ description: 'Consultoría', quantity: 1, unitPrice: 25000, cabysCode: '8314300000000' }],
})
invoice.haciendaStatus // 'aceptado'

Características (v1.0)

  • Emisión completa: Factura (FE), Tiquete (TE), Nota de Crédito (NC), Nota de Débito (ND) y Factura de Exportación (FEE).
  • issueAndWait — emite y espera (poll) la respuesta de Hacienda, encapsulando el ciclo fiscal asíncrono.
  • Ambientes estilo Stripe — el prefijo de la key (wpk_test_ / wpk_live_) define Sandbox vs Producción; datos aislados.
  • IdempotenciaIdempotency-Key para que un reintento nunca duplique un comprobante.
  • Reintentos automáticos con backoff exponencial ante 429 / 5xx / errores de red.
  • Errores tipados con code, status y requestId (rastreables en soporte).
  • Catálogo, clientes, inventario y sucursales.
  • Referencia Hacienda — validar CABYS, contribuyentes y exoneraciones.
  • 100% tipado, ESM + CJS, cero dependencias en runtime.

Requisitos

| Requisito | Versión | | -------------- | ---------------------------------------------------- | | Node.js | ≥ 18 (usa fetch nativo) | | Runtimes | Node, Bun, Deno y entornos edge con fetch | | Una API key | de WePOS — ver abajo |

Obtener una API key

La API key se solicita y administra desde el panel de WePOS:

pos.wecodecr.com → Configuración → API Keys → Crear API key

Al crearla eliges sus scopes (permisos mínimos) y su ambiente:

  • wpk_test_…Sandbox (pruebas, sin validez fiscal).
  • wpk_live_…Producción (comprobantes con validez fiscal).

Guarda la key de forma segura (se muestra una sola vez) y nunca la expongas en el cliente/navegador — úsala solo desde tu backend.

Instalación

npm install @wepos/sdk
# pnpm add @wepos/sdk · yarn add @wepos/sdk · bun add @wepos/sdk

Inicio rápido

import { WeposClient } from '@wepos/sdk'

const wepos = new WeposClient({
  apiKey: process.env.WEPOS_API_KEY!, // wpk_test_… (Sandbox) o wpk_live_… (Producción)
})

const invoice = await wepos.invoices.issueAndWait({
  documentType: 'FE',
  customer: {
    idType: 'CEDULA_JURIDICA',
    idNumber: '3101123456',
    name: 'Cliente S.A.',
    email: '[email protected]',
  },
  lines: [
    { description: 'Consultoría', quantity: 1, unitPrice: 25000, cabysCode: '8314300000000' },
  ],
})

console.log(invoice.haciendaStatus) // 'aceptado' | 'rechazado'
console.log(invoice.claveNumerica)

Ambientes (estilo Stripe)

El ambiente lo determina el prefijo de la API key — no se configura aparte:

| Key | Ambiente | Validez fiscal | | -------------- | ---------- | -------------- | | wpk_test_... | Sandbox | No (pruebas) | | wpk_live_... | Producción | Sí |

Los datos están aislados por ambiente: una key de sandbox nunca ve comprobantes de producción.

Configuración

new WeposClient({
  apiKey: 'wpk_live_...',
  baseUrl: 'https://pos.wecodecr.com', // default
  timeoutMs: 30_000,                   // default
  maxRetries: 2,                       // reintenta 429 / 5xx / red, con backoff
})

Cobertura de la API

| Recurso | Estado | Scope requerido | | ------------------------------- | :----: | ---------------------- | | Facturas (FE/TE/NC/ND/FEE) | ✅ | invoices:read/write | | Clientes | ✅ | customers:read/write | | Productos | ✅ | products:read | | Inventario | ✅ | inventory:read | | Sucursales | ✅ | branches:read | | Referencia (CABYS, cédulas…) | ✅ | reference:read | | Webhooks (verificación) | 🔜 | (v1.1) | | Ventas POS / sesiones de caja | 🔜 | (v1.4) | | Cuentas por cobrar / pagar | 🔜 | (v1.4) | | Reportes y exportación contable | 🔜 | (v1.4) |

Recursos

Facturas — wepos.invoices

await wepos.invoices.create(input, { idempotencyKey })   // emite y retorna de inmediato
await wepos.invoices.issueAndWait(input, { timeoutMs, pollIntervalMs }) // emite y espera a Hacienda
await wepos.invoices.get(id)                              // estado + detalle
await wepos.invoices.list({ limit, documentType })
await wepos.invoices.getXml(id)                           // XML firmado + respuesta Hacienda
await wepos.invoices.createCreditNote(id, { reason, fullReversal })
await wepos.invoices.createDebitNote(id, { reason, referenceCode, lines })
await wepos.invoices.export(input)                        // Factura de Exportación (FEE)

Clientes — wepos.customers

await wepos.customers.create({ idType, idNumber, name, email })
await wepos.customers.list({ search, limit })

Catálogo e inventario

await wepos.products.list({ search, limit })
await wepos.inventory.list({ productId, warehouseId, search, limit })
await wepos.branches.list()  // para obtener el branchId a usar en emisiones

Referencia Hacienda — wepos.reference

await wepos.reference.getCabys('8314300000000')   // valida código, retorna tarifa IVA
await wepos.reference.searchCabys('consultoría')  // busca por texto
await wepos.reference.getTaxpayer('3101123456')   // valida contribuyente
await wepos.reference.getExoneration('AUT-123')   // consulta exoneración DGT

Partner — WePOS como backend fiscal embebido

Si tenés tu propio SaaS multi-tenant y querés que WePOS sea el motor de facturación electrónica detrás de escena (tus clientes nunca entran a WePOS: gestionan todo desde tu SaaS), usá la superficie Partner. Con una sola credencial (la partner key) tu SaaS aprovisiona y administra muchos tenants, cada uno con su propio certificado, credenciales de Hacienda y comprobantes — todo guardado en WePOS.

Dos tipos de credenciales

| Credencial | Prefijo | Para qué | De dónde sale | |---|---|---|---| | Partner key | wppk_test_… / wppk_live_… | Aprovisionar y configurar tenants (plano de control) | El super-admin de WePOS la genera en /partners | | Tenant key | wpk_test_… / wpk_live_… | Emitir comprobantes de UN tenant (plano de datos) | La devuelve partner.tenants.create(), o se genera por tenant |

La partner key solo puede tocar sus propios tenants (aislamiento estricto: un tenant de otro partner responde 404). Guardala como secreto de servidor.

Flujo de integración (end-to-end)

import { WeposClient } from '@wepos/sdk'

// El SaaS usa su PARTNER key (no una de tenant).
const wepos = new WeposClient({ apiKey: process.env.WEPOS_PARTNER_KEY! }) // wppk_…

// 1) Aprovisionar el tenant fiscal del cliente final del SaaS.
//    Crea el negocio completo (casa matriz, actividades, consecutivos…) y
//    devuelve una tenant key de datos lista para emitir.
const { tenantId, tenantApiKey } = await wepos.partner.tenants.create({
  name: 'Soda La Esquina',
  idType: 'CEDULA_JURIDICA',
  idNumber: '3101123456',
  adminEmail: '[email protected]',
  location: { province: '1', canton: '01', district: '01' }, // códigos Hacienda (o nombres: 'San José'/'Central'/'Carmen')
  activities: [{ codigo: '5610.0', tipo: 'P' }],   // opcional
})

// 2) Configurar Hacienda — el cliente sube su firma + credenciales desde tu UI.
//    Funciona por AMBIENTE: primero STAGING para probar, luego PRODUCTION.
await wepos.partner.tenants.setCredentials(tenantId, {
  environment: 'STAGING',
  user: '[email protected]',
  password: '••••••',
})
await wepos.partner.tenants.uploadCertificate(tenantId, {
  environment: 'STAGING',
  p12Base64: fs.readFileSync('firma.p12').toString('base64'),
  pin: '1234',
})

// 3) Ver el estado de configuración (sin exponer secretos).
const cfg = await wepos.partner.tenants.get(tenantId)
// cfg.environments → [{ environment: 'STAGING', hasCredentials: true, hasCertificate: true, certExpiresAt }]

// 3.5) MIGRACIÓN — si el negocio viene de otro sistema, continuá su numeración.
//      value = último número YA emitido; el próximo comprobante sale value+1.
await wepos.partner.tenants.setConsecutives(tenantId, {
  environment: 'PRODUCTION',
  counters: [
    { branchCode: '001', terminalCode: '00001', documentType: 'FE', value: 400 }, // próxima FE = 401
    { branchCode: '001', terminalCode: '00001', documentType: 'TE', value: 1250 },
  ],
})
// Consultar los contadores actuales:
const { counters } = await wepos.partner.tenants.getConsecutives(tenantId, 'PRODUCTION')

// 4) Cuando el cliente pasa a producción: repetí el paso 2 con environment:'PRODUCTION'
//    y promové el ambiente por defecto del tenant.
await wepos.partner.tenants.update(tenantId, { defaultEnvironment: 'PRODUCTION' })

// 5) Emitir por ese tenant — con la tenant key de datos (plano de datos normal).
const tenant = new WeposClient({ apiKey: tenantApiKey }) // wpk_…
const invoice = await tenant.invoices.issueAndWait({
  documentType: 'FE',
  customer: { idType: 'CEDULA_JURIDICA', idNumber: '3101003937', name: 'Cliente S.A.' },
  lines: [{ description: 'Casado', quantity: 1, unitPrice: 3500, cabysCode: '2312000000300' }],
})
console.log(invoice.claveNumerica, invoice.haciendaStatus)

// 6) ¿El tenant se creó bajo la partner key equivocada (ej. live) y necesitás
//    emitir en sandbox? Pedí una data key del ambiente que querés — sin recrear
//    el tenant. El ambiente lo manda la data key (estilo Stripe), no el tenant.
const { tenantApiKey: sandboxKey } = await wepos.partner.tenants.issueKey(tenantId, { environment: 'STAGING' })
const sandbox = new WeposClient({ apiKey: sandboxKey }) // wpk_test_… → emite en STAGING

Métodos de wepos.partner.tenants

| Método | Qué hace | |---|---| | create(input) | Aprovisiona un tenant fiscal completo; devuelve tenantId + tenantApiKey (salvo issueApiKey: false) | | list() | Lista los tenants de este partner | | get(tenantId) | Config + estado por ambiente (hasCredentials/hasCertificate/certExpiresAt) | | update(tenantId, { defaultEnvironment?, activities? }) | Promueve el ambiente por defecto y/o reemplaza actividades | | setCredentials(tenantId, { environment?, user, password }) | Credenciales ATV por ambiente | | uploadCertificate(tenantId, { environment?, p12Base64, pin }) | Certificado .p12 (base64) por ambiente; valida el archivo + PIN y que la cédula del cert coincida con el emisor (evita -60) | | getConsecutives(tenantId, environment?) | Lista los contadores de consecutivos por ambiente (con el próximo consecutivo de 20 dígitos) | | setConsecutives(tenantId, { environment?, counters }) | Migración: fija el consecutivo de arranque de forma atómica; value = último emitido, debe ser ≥ el actual | | issueKey(tenantId, { environment?, name?, scopes? }) | Emite una nueva data key (wpk_…) para el tenant, por ambiente. Mueve un tenant existente entre sandbox y producción sin recrearlo | | listKeys(tenantId) | Lista las data keys del tenant (solo metadatos, nunca el secreto) | | revokeKey(tenantId, keyId) | Revoca una data key (inmediato e irreversible) |

Certificado: el .p12 y su PIN se guardan encriptados en WePOS y nunca se devuelven. Manejalos como pass-through en tu SaaS (no los persistas ni loguees). El environment por defecto es el de la partner key.

Actividad económica (emisor y receptor)

Un contribuyente puede tener varias actividades registradas en Hacienda. Puedes:

  • Elegir con cuál actividad emite el emisor → activityCode (debe ser una actividad registrada del emisor; si se omite, usa la principal).
  • Enviar la actividad del compradorreceptorActivityCode (opcional, v4.4).

Combínalo con reference.getTaxpayer() para que el comprador elija entre sus actividades:

// 1. Traer las actividades del comprador desde Hacienda
const tp = await wepos.reference.getTaxpayer('3101003937')
// tp.actividades → [{ codigo: '4730.0', descripcion: '…', tipo: 'P' }, …]

// 2. Emitir indicando la actividad del receptor (y opcionalmente la del emisor)
await wepos.invoices.create({
  documentType: 'FE',
  customer: { id: customerId },
  activityCode: '4610.0',            // actividad del EMISOR (si tiene varias)
  receptorActivityCode: tp.actividades[0].codigo, // actividad del RECEPTOR
  lines: [/* … */],
})

Idempotencia

Pasa una idempotencyKey al emitir: un reintento con la misma key no duplica el comprobante.

await wepos.invoices.create(input, { idempotencyKey: 'orden-4821' })

Manejo de errores

import { WeposApiError, WeposTimeoutError } from '@wepos/sdk'

try {
  await wepos.invoices.create(input)
} catch (err) {
  if (err instanceof WeposApiError) {
    console.error(err.code, err.status, err.message, err.requestId)
    if (err.isRateLimit) { /* 429 */ }
    if (err.isAuth) { /* 401 / 403 — revisar key/scopes */ }
  } else if (err instanceof WeposTimeoutError) {
    // Hacienda tardó; consulta el estado más tarde con invoices.get(err.invoiceId)
  }
}

Todos los errores exponen el code estable de WePOS, el status HTTP y el requestId.

Reintentos y timeouts

  • El SDK reintenta automáticamente ante 429, 5xx y errores de red, con backoff exponencial y respeto del header Retry-After. Configurable con maxRetries.
  • Las escrituras solo deben reintentarse con una idempotencyKey (lo hace por ti issueAndWait).
  • Cada request tiene un timeoutMs (default 30s). issueAndWait tiene su propio timeoutMs para la espera de Hacienda.

TypeScript

El SDK incluye tipos completos. Los de la superficie pública están curados a mano para la mejor DX, pero reflejan el OpenAPI publicado en /api/v1/openapi. Para cruzarlos contra el contrato real o expandir a nuevos endpoints, regenera desde el spec vivo:

WEPOS_BASE_URL=https://pos.wecodecr.com npm run gen:types

Roadmap

El orden refleja prioridad por valor para integradores. Sugerencias en [email protected].

✅ v1.0 — Núcleo de emisión (actual)

Emisión FE/TE/NC/ND/FEE, issueAndWait, clientes, catálogo, inventario, sucursales y referencia Hacienda. DX: idempotencia, reintentos, errores tipados, ESM+CJS, tipos completos.

🔜 Webhooks y eventos

  • wepos.webhooks.verify(rawBody, signatureHeader, secret) — verificación de firma HMAC estilo Stripe (x-wepos-signature: t=…,v1=…), con tolerancia anti-replay.
  • Tipos de eventos fiscales (document.accepted, document.rejected, document.error, …).
  • Handlers listos para Next.js y Express.

✅ v1.2 — Partner (backend fiscal embebido)

Superficie de plano de control para SaaS partner (partner key wppk_…): partner.tenants.create/list/get/update + setCredentials/uploadCertificate

✅ v1.3 — Migración de consecutivos (Partner)

partner.tenants.getConsecutives/setConsecutives — fijar el consecutivo de arranque cuando un negocio migra desde otro sistema, por ambiente (STAGING/PRODUCTION), de forma atómica y monótona. Ver Partner.

✅ v1.4 — Data keys por ambiente (Partner)

partner.tenants.issueKey/listKeys/revokeKey — emitir/listar/revocar data keys (wpk_…) de un tenant existente por ambiente. Mueve un tenant entre sandbox y producción sin recrearlo.

🔜 Próximo — Listados y paginación

  • Auto-paginación / async iterators (for await (const inv of wepos.invoices.iterate())).
  • Filtros adicionales: rango de fechas, estado de Hacienda, sucursal, cliente.

🔜 Más recursos de negocio

  • Ventas POS y sesiones de caja, devoluciones e impresión.
  • Cuentas por cobrar / pagar (pagos, estados de cuenta, aging).
  • Reportes (ventas, impuestos, reporte Z, libros, exportación contable).
  • Catálogo avanzado (listas de precios, promociones, combos) y compras (procurement).

🔭 v2.0 — Apps móviles y desktop

  • Auth de dispositivos (login/refresh) con refresco automático del token.
  • Change-feed / sync con cursores para apps offline-first.
  • Subida de imágenes (logo, productos) y modo contingencia.

🌎 Futuro

  • SDKs de PHP y Python generados desde el OpenAPI.
  • CLI wepos para emitir/consultar desde terminal y CI.
  • Modo mock para tests de integradores sin tocar Hacienda.

Versionado

Seguimos SemVer: los cambios incompatibles solo ocurren en versiones major. Consulta el historial en la pestaña de versiones en npm.

Soporte

  • 📦 npm: https://www.npmjs.com/package/@wepos/sdk
  • 🌐 Plataforma: https://pos.wecodecr.com
  • ✉️ [email protected]

Licencia

MIT © WeCode CR