@tuago/node
v0.4.0
Published
Official Tuago Node/TypeScript SDK — WhatsApp-native payment collection gateway.
Maintainers
Readme
@tuago/node
Official Node/TypeScript SDK for Tuago — the WhatsApp-native payment collection gateway. Server-side only (uses your secret key). Money is integer minor units (kobo) as strings.
npm install @tuago/nodeQuickstart
import { Tuago } from "@tuago/node";
const tuago = new Tuago({ secretKey: process.env.TUAGO_SECRET_KEY! }); // sk_test_… / sk_live_…
// Collect via bank transfer — returns a dynamic virtual account to show the payer.
const charge = await tuago.charges.create(
{ amount: 1_850_000, reference: orderId, channel: "BANK_TRANSFER" },
{ idempotencyKey: orderId },
);
console.log(charge.virtualAccount); // { bankName, accountNumber, accountName, expiresAt }Split settlement (platforms)
Route a collection through a subaccount: the vendor's share settles to their bank, your commission to yours — one payment, automatic.
const sub = await tuago.subaccounts.create({
businessName: "Mama Put Kitchen",
bankCode: "058", accountNumber: "0123456789",
splitType: "PERCENTAGE", splitValue: 1000, // you take 10% (bps)
});
await tuago.charges.create({
amount: 1_850_000, reference: orderId,
subaccount: sub.id,
transactionCharge: 100_000, // optional flat commission override (kobo)
});Headless WhatsApp checkout
Get raw payment instructions + every available method to render directly in chat (no hosted page):
const session = await tuago.checkout.create({
amount: 1_850_000, customerEmail: "[email protected]",
mode: "headless", subaccount: sub.id,
});
session.paymentInstructions; // VA to print in WhatsApp
session.paymentMethods; // [{ method:"bank_transfer", ... }, { method:"ussd", ... }, { method:"card", ... }]Webhooks
Verify the signature with the raw request body (never re-serialize):
import { constructEvent } from "@tuago/node";
app.post("/tuago-webhook", express.raw({ type: "application/json" }), (req, res) => {
try {
const event = constructEvent(req.body, req.header("x-ollie-signature"), process.env.TUAGO_WEBHOOK_SECRET!);
if (event.type === "charge.success") {
// payment landed — confirm the order, reply in WhatsApp
}
res.sendStatus(200);
} catch {
res.sendStatus(400); // bad signature
}
});Recurring (plans + subscriptions)
Tuago does not charge a saved card — no rail here can. Each period raises an ordinary charge with its own virtual account, and the subscriber paying it is what renews the subscription.
const plan = await tuago.subscriptions.createPlan({
name: "Gold membership",
amount: 500_000, // kobo
interval: "MONTHLY",
});
// share this and customers subscribe themselves:
// https://<your checkout host>/subscribe/${plan.slug}
// or subscribe someone directly — the first period is billed immediately
const sub = await tuago.subscriptions.create({ planId: plan.id, customerEmail: "[email protected]" });Then listen for subscription.charge_due (carries the period's account number to send on),
subscription.charge_overdue (chase them) and subscription.renewed (extend their access).
Group payments (split one bill among friends)
One bill, several payers. Each friend picks any amount up to what is still owed and gets their own account number, so no payment is lost and each one can be refunded. Contributions are held until the pool closes, then all paid out to you or all refunded.
const pool = await tuago.pools.create({
title: "Dinner at Nok",
amount: 6_000_000, // kobo, the whole bill
expiresInHours: 72,
expiryRule: "REFUND", // if it falls short: "REFUND" everyone (default) or "RELEASE" what came in
reference: orderId, // the same reference returns the same pool
});
pool.url; // send this to the customer; friends pay on that page
await tuago.pools.contributions(pool.id); // who has paid
await tuago.pools.close(pool.id, "REFUND"); // or "RELEASE", before the deadlineA customer on a hosted checkout can split it themselves:
const split = await tuago.checkout.split(session.id, { organizerName: "Ada" });
// share https://<your checkout host>/pool/${split.slug}Listen for pool.funded (the bill is fully paid: event.data.reference is your pool reference,
or event.data.checkout_reference when a checkout was split), pool.refunded (it fell short and
everyone was refunded), pool.released (you closed it and took what was collected) and
pool.contribution_paid (one friend's payment landed). While a pool is open you cannot accept,
reject or refund a single contribution; the pool moves them together.
Refunds
await tuago.refunds.create({ chargeReference: orderId, reason: "customer cancelled" });
// full or partial; unwinds every split leg server-sideErrors
Every failure throws TuagoError with a stable .code (merchant_cap_exceeded,
core_unavailable, idempotency_conflict, …) and .httpStatus. Signature failures throw
TuagoSignatureError.
Resources
charges · subaccounts · subscriptions · refunds · checkout · balance · settlements · banks
