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

@nicotordev/payku

v1.2.0

Published

SDK en TypeScript para integrar Payku, la pasarela de pagos LATAM, en aplicaciones web

Readme

Payku — Cliente API para TypeScript

npm CI License: MIT Bun TypeScript

SDK en TypeScript de código abierto para integrar Payku, la pasarela de pagos LATAM (Chile, Perú y Venezuela).

Instalación

bun add @nicotordev/payku

Configuración

Por país (recomendado)

Fija la moneda y expone solo los módulos soportados por ese mercado:

import Payku from "@nicotordev/payku";

const payku = Payku.forCountry("CL", {
  publicToken: process.env.PAYKU_PUBLIC_TOKEN!,
  privateToken: process.env.PAYKU_PRIVATE_TOKEN!,
  environment: "production",
});

// currency implícita: CLP — no hace falta pasarla
await payku.transactions.create({
  amount: 1000,
  payment: 1,
  order: "orden-001",
  email: "[email protected]",
  subject: "Compra test",
  urlreturn: "https://tu-sitio.com/return",
  urlnotify: "https://tu-sitio.com/notify",
});

// También desde .env
const fromEnv = Payku.fromEnvForCountry("CL");

| País | Cliente | Moneda | Extra | | ---- | ---------------- | ------ | --------------------------------------------------- | | CL | PaykuChile | CLP | suscripciones, marketplace, mall, escrow, withdraw… | | PE | PaykuPeru | PEN | core compartido | | VE | PaykuVenezuela | VES | transactions.confirmOnSite |

Si llamás un módulo no soportado (p. ej. wallet.withdraw en Perú), el SDK lanza PaykuUnsupportedFeatureError.

Modo global (multi-país)

import Payku from "@nicotordev/payku";

const payku = new Payku(
  process.env.PAYKU_PUBLIC_TOKEN!,
  process.env.PAYKU_PRIVATE_TOKEN!,
  "production",
);

// o desde variables de entorno (Bun carga .env automáticamente)
const paykuFromEnv = Payku.fromEnv();

En modo global pasás currency en cada request (CLP | PEN | VES).

Autenticación y firma

Bearer (token público)

Casi todas las requests llevan:

Authorization: Bearer TOKEN_PUBLICO

El SDK lo inyecta automáticamente con publicToken (constructor, forCountry o .env).

Sign (HMAC-SHA256)

Endpoints sensibles envían además el header Sign, calculado con el token privado (misma lógica que buildSign / HttpClient):

  1. encodeURIComponent("/api/...") del path
  2. Parámetros a firmar:
    • GET → query
    • POST / PUT / DELETE → body (si no hay body, solo el path)
  3. Keys ordenadas alfabéticamente; se omiten null/undefined y objetos/arrays
  4. Cada key/valor se serializa vía URLSearchParams (percent-encoding, p. ej. espacios → +, @ → %40)
  5. Concatenar pathCodificado&key=value&... (o solo el path si no hay params)
  6. HMAC-SHA256(concat, privateToken) en hex

El SDK firma solo donde corresponde (signed: true). Para integraciones custom exporta buildSign:

import { buildSign } from "@nicotordev/payku";

const sign = buildSign(
  "/api/suclient",
  {
    email: "[email protected]",
    name: "John Doe",
    phone: "923122312",
    address: "Moneda 101",
    country: "Chile",
    region: "Metropolitana",
    city: "Santiago",
    postal_code: "850000",
    additional_parameters: {
      parameter_1: "example",
      parameter_2: "example 2",
    },
  },
  process.env.PAYKU_PRIVATE_TOKEN!,
);

// Header: Sign: <sign>

Matriz Sign por módulo (SDK)

| Módulo | Sign | Notas | | -------------------------------------------- | ------- | ----------------------------------------------------------------- | | transactions | No | create/get/list (y On-Site VE) | | banks / paymentMethods | No | Catálogo | | conciliation | No | | | escrow / events | No | | | wallet | Sí | payout, withdraw, balance, movements, get payout | | subscriptions / consumptionSubscriptions | Sí | CRUD clientes, planes, tarjetas, txs | | nullification | Sí | create y get (GET también: docs omiten Sign, sandbox responde waiting sign) | | mall | Parcial | create sí; get no (sandbox: sin Sign; docs PHP/JS muestran Sign opcional) | | marketplace | Parcial | Solo maclient update (PUT); create/delete/get y maaffiliation / tx sin Sign (sandbox) |

Referencia oficial y colección Postman: docs.payku.com · colección CL · environment.

Transacciones

// Con forCountry("CL") — currency ya fijada
const order = await payku.transactions.create({
  email: "[email protected]",
  order: "orden-001",
  subject: "Compra test",
  amount: 1000,
  payment: 1,
  urlreturn: "https://tu-sitio.com/return",
  urlnotify: "https://tu-sitio.com/notify",
});

// Redirigir al pagador
console.log(order.url);

Catálogo

const methods = await payku.paymentMethods.list({ currency: "clp" });
const banks = await payku.banks.list({ currency: "clp" });

Webhooks

const result = await payku.webhooks.verifyNotify(payload, {
  expectedOrder: "orden-001",
  expectedAmount: 1000,
});

if (result.valid) {
  // Pago verificado contra la API de Payku
}

Errores y respuestas

Según la introducción de la API Payku, no confíes solo en el código HTTP (p. ej. 200). Muchas respuestas de error llegan con HTTP 200 y un JSON de negocio:

| status en el JSON | Significado | | ---------------------------------------- | ------------------------------------------ | | "success" / "pending" / "register" | Flujo OK (según endpoint) | | "failed" | Error de negocio (type, message_error) |

Este SDK ya inspecciona el body en HttpClient: si status === "failed" (o type === "Unauthorized"), lanza un error tipado en lugar de devolver el JSON.

try / catch con el SDK

import Payku, { PaykuAPIError, isPaykuError } from "@nicotordev/payku";

const payku = Payku.forCountry("CL", {
  publicToken: process.env.PAYKU_PUBLIC_TOKEN!,
  privateToken: process.env.PAYKU_PRIVATE_TOKEN!,
  environment: "sandbox",
});

try {
  await payku.transactions.create({
    amount: 1000,
    payment: 1,
    order: "orden-001",
    email: "[email protected]",
    subject: "Compra test",
  });
} catch (error) {
  if (error instanceof PaykuAPIError) {
    console.error(error.message, error.statusCode, error.type);
    console.error(error.response); // JSON original de Payku
    return;
  }

  if (isPaykuError(error)) {
    console.error(error.message, error.statusCode, error.type);
    return;
  }

  throw error;
}

Inspeccionar JSON crudo

Si lees respuestas API fuera del cliente (proxy, log), usa los type guards públicos:

import {
  extractPaykuErrorMessage,
  isPaykuFailedResponse,
  isPaykuUnauthorizedResponse,
} from "@nicotordev/payku";

function handleRawPaykuJson(data: unknown) {
  if (isPaykuFailedResponse(data)) {
    console.error(extractPaykuErrorMessage(data), data.type);
    return;
  }

  if (isPaykuUnauthorizedResponse(data)) {
    console.error(extractPaykuErrorMessage(data));
  }
}

Nota: el payload de urlnotify es manipulable. Para decidir si un pago es válido usa payku.webhooks.verifyNotify(), que reconsulta la API.

Wallet (Chile)

const balance = await payku.wallet.balance.get();
const movements = await payku.wallet.movements.list({ page: 1, per_page: 20 });

Anulación (Chile)

const payku = Payku.forCountry("CL", {
  publicToken: process.env.PAYKU_PUBLIC_TOKEN!,
  privateToken: process.env.PAYKU_PRIVATE_TOKEN!,
  environment: "sandbox",
});

const nullify = await payku.nullification.create({
  id: "trxpr2a45s1dytg1",
  amount: 25000,
  subject: "anulación transacción",
});

Escrow (Chile)

const payku = Payku.forCountry("CL", {
  publicToken: process.env.PAYKU_PUBLIC_TOKEN!,
  privateToken: process.env.PAYKU_PRIVATE_TOKEN!,
  environment: "sandbox",
});

await payku.escrow.authorize({
  transactions: ["trx3b4d77b43acd9a720", "trx3b4d77b43acd9a385"],
});

Suscripciones (Chile)

const client = await payku.subscriptions.clients.create({
  email: "[email protected]",
  name: "Cliente Test",
});

const subscription = await payku.subscriptions.subscriptions.create({
  plan: "pl...",
  client: client.id as string,
});

Eventos (Chile)

Crear un evento y consultar su detalle:

const payku = Payku.forCountry("CL", {
  publicToken: process.env.PAYKU_PUBLIC_TOKEN!,
  privateToken: process.env.PAYKU_PRIVATE_TOKEN!,
  environment: "production",
});

const created = await payku.events.create({
  event: "98374",
  name: "Event",
  date_event: "2023-12-20",
  date_closing_sales: "2023-12-19 23:59:00",
  date_payment: "2023-12-22",
  affiliation: [
    ["[email protected]", 50],
    ["[email protected]", 50],
  ],
});

const detail = await payku.events.get(created.id);

Nota: La respuesta de events.create() usa affiliation, mientras que el detalle obtenido con events.get() usa affiliations.

Especificación del SDK

Ver docs/sdk-spec.md para arquitectura, convenciones y roadmap.

Referencia API

Generar documentación TypeDoc:

bun run docs:api

La salida queda en docs/api/.

Tests

bun run test             # unit (default)
bun run test:integration # smoke sandbox por módulo (tokens + PAYKU_ENVIRONMENT=sandbox)

Contribuir

Pull requests y issues son bienvenidos. Empieza por:

Licencia

MIT © Nicolas Torres