@nicotordev/payku
v1.2.0
Published
SDK en TypeScript para integrar Payku, la pasarela de pagos LATAM, en aplicaciones web
Maintainers
Readme
Payku — Cliente API para 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/paykuConfiguració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_PUBLICOEl 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):
encodeURIComponent("/api/...")del path- Parámetros a firmar:
- GET → query
- POST / PUT / DELETE → body (si no hay body, solo el path)
- Keys ordenadas alfabéticamente; se omiten
null/undefinedy objetos/arrays - Cada key/valor se serializa vía
URLSearchParams(percent-encoding, p. ej. espacios →+,@→%40) - Concatenar
pathCodificado&key=value&...(o solo el path si no hay params) 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
urlnotifyes manipulable. Para decidir si un pago es válido usapayku.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()usaaffiliation, mientras que el detalle obtenido conevents.get()usaaffiliations.
Especificación del SDK
Ver docs/sdk-spec.md para arquitectura, convenciones y roadmap.
Referencia API
Generar documentación TypeDoc:
bun run docs:apiLa 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:
- Wiki (guías ampliadas)
- CONTRIBUTING.md
- Code of Conduct
- SUPPORT.md
- Discussions
Licencia
MIT © Nicolas Torres
