olympo-payments
v1.0.1
Published
Abstracción de pagos de la suite Cauce sobre Mercado Pago (cuenta CENTRAL, Colombia/COP). Framework-agnóstica: la usan NestJS (Iris/Fiar) y Hapi.
Readme
olympo-payments
Abstracción de pagos de la suite Cauce sobre Mercado Pago (cuenta CENTRAL, Colombia / COP, sin OAuth).
Framework-agnóstica: la usan NestJS (Iris/Fiar) y Hapi. No importa ningún framework HTTP; recibe headers/query/body como datos planos.
Instalación (monorepo)
// package.json del consumidor
"dependencies": {
"olympo-payments": "workspace:*"
}SDK base: mercadopago@^2.12.0 (la misma major que ya usan Iris y Fiar).
Uso
import { MercadoPagoGateway } from "olympo-payments";
const gateway = new MercadoPagoGateway({
// todo opcional: por defecto lee de env
// accessToken -> MP_ACCESS_TOKEN (o MP_ACCESS_TOKEN_TEST en sandbox)
// webhookSecret-> MP_WEBHOOK_SECRET
// sandbox -> MP_SANDBOX_MODE === "true"
});Checkout Pro (pago único — pedidos / compra puntual)
const pref = await gateway.createCheckout({
items: [{ title: "Pedido #123", quantity: 1, unit_price: 150000 }], // currency_id default COP
externalReference: "ord-123",
notification_url: "https://api.tu-servicio/webhooks/mercadopago",
metadata: { storeId: "s1", orderId: "ord-123" },
back_urls: { success: "https://app/ok", failure: "https://app/fail", pending: "https://app/wait" },
statement_descriptor: "CAUCE",
});
// → { id, init_point, sandbox_init_point } -> redirige al init_pointSuscripción recurrente (planes SaaS — PreApproval)
const sub = await gateway.createSubscription({
payerEmail: "[email protected]",
reason: "Plan Cauce Pro — Mensual",
auto_recurring: { frequency: 1, frequency_type: "months", amount: 29900, currency: "COP" },
externalReference: "user-42|PRO|MONTHLY",
back_url: "https://app/payment/success", // obligatorio, URL pública
});
// → { id, init_point, status }Consultas de estado
const pago = await gateway.getPayment(mpPaymentId); // { id, status, external_reference, ... }
const sus = await gateway.getPreapproval(preapprovalId); // { id, status, external_reference, ... }Webhooks
// 1) Validar firma (timing-safe, manifest oficial de MP)
const { valid, reason } = gateway.verifyWebhook({
headers: req.headers, // necesita x-signature y x-request-id
query: req.query, // necesita data.id
rawBody: req.rawBody,
});
if (!valid) return 401;
// 2) Normalizar el payload
const evt = gateway.parseWebhook(req.body);
// → { kind: "payment" | "subscription", mpId, status, externalReference }
// 3) Estado real (el webhook NO lo trae completo)
const info = evt.kind === "payment"
? await gateway.getPayment(evt.mpId)
: await gateway.getPreapproval(evt.mpId);
const estado = gateway.mapStatus(info.status); // "aprobado" | "rechazado" | "pendiente"Firma x-signature
Manifest oficial validado: id:<data.id>;request-id:<x-request-id>;ts:<ts>;
HMAC-SHA256 con MP_WEBHOOK_SECRET, comparado timing-safe contra el v1 del header
x-signature (ts=<unix>,v1=<hash>). Mismo enfoque que olympo-contracts/signature.ts.
Idempotencia
MP puede reenviar un mismo webhook varias veces. Usa el guard con un store inyectable
(espeja el patrón wasAlreadyApproved de Iris: chequear antes de acreditar):
import { wasAlreadyProcessed, InMemoryIdempotencyStore } from "olympo-payments";
const store = new InMemoryIdempotencyStore(); // en prod: Postgres/Redis
if (await wasAlreadyProcessed(evt.mpId, store)) return 200; // ya procesado, ignorar
// ... acreditar el pago una sola vez ...Las creaciones (createCheckout/createSubscription) ya envían el header
x-idempotency-key derivado del externalReference para no duplicar recursos en reintentos.
Métodos de pago Colombia
No hay que listarlos manualmente. Con Checkout Pro, Mercado Pago ofrece de forma nativa
tarjeta, PSE, Nequi y Bancolombia según lo habilitado en la cuenta CENTRAL. El mapa
COLOMBIA_PAYMENT_METHODS es solo documental (para UI propia o validaciones opcionales).
Eventos del ecosistema
Re-exporta de olympo-contracts los tipos de payload de los eventos de pago
(PagoIniciadoPayload, PagoAprobadoPayload, PagoRechazadoPayload,
SuscripcionActivadaPayload, SuscripcionCanceladaPayload) y EVENTS, además de
signPayload/verifySignature para firmar los eventos que publiques a HubCentral.
Scripts
| Script | Acción |
| ------------- | --------------------------------------- |
| build | tsup → ESM + CJS + DTS (dist/) |
| typecheck | tsc --noEmit |
| test | node --test sobre dist/ (build antes) |
