Node.js SDK
Official TypeScript client with retries, idempotency and webhook verification
The official Node.js SDK wraps the same REST API documented here. Everything is also reachable with plain HTTP — the SDK just adds retries, idempotency keys, auto-pagination and webhook signature verification.
Status: the
southbillpackage is not on the public npm registry yet. Until the first release lands you can install it straight from the repository tarball, or use the plain REST examples in the other articles.
Install
npm install southbill
Requires Node.js 18 or newer.
Create a checkout session
import { Southbill } from "southbill";
const southbill = new Southbill(process.env.SOUTHBILL_API_KEY);
const session = await southbill.checkout.sessions.create({
amount: 4900,
currency: "EUR",
customer_email: "ada@acme.com",
success_url: "https://acme.com/thanks",
});
console.log(session.checkout_url);
Available resources
| Namespace | Methods |
|---|---|
checkout.sessions |
create, retrieve, list, expire |
customers |
create, retrieve, update, list, del |
invoices |
create, retrieve, update, list, send, void, markPaid |
products |
create, retrieve, update, list |
payments |
retrieve, list |
refunds |
create |
subscriptions |
create, retrieve, list, cancel |
events |
retrieve, list, replay |
Payouts, bank details, KYC and API-key management are deliberately absent — those actions stay merchant-controlled in the dashboard and are not exposed to any key or app.
Idempotency
Every POST sends an Idempotency-Key automatically. Supply your own so retries
across processes collapse into one operation:
await southbill.invoices.create(params, { idempotencyKey: `inv-${orderId}` });
Pagination
for await (const invoice of southbill.invoices.autoPagingEach({ status: "open" })) {
console.log(invoice.id);
}
Errors
Network failures, 429 and 5xx are retried twice with exponential backoff.
Everything else throws a SouthbillError carrying status, type, param and
requestId.
import { SouthbillError } from "southbill";
try {
await southbill.refunds.create({ payment: "pi_123", amount: 500 });
} catch (error) {
if (error instanceof SouthbillError) {
console.error(error.status, error.type, error.param, error.requestId);
}
}
Verify webhooks
Always verify the raw request body — not a re-serialized object.
import express from "express";
import { Southbill, SouthbillSignatureError } from "southbill";
const southbill = new Southbill(process.env.SOUTHBILL_API_KEY);
const app = express();
app.post("/webhooks/southbill", express.raw({ type: "*/*" }), (req, res) => {
try {
const event = southbill.webhooks.constructEvent({
payload: req.body,
signature: req.header("X-Southbill-Signature") ?? "",
secret: process.env.SOUTHBILL_WEBHOOK_SECRET,
});
if (event.type === "invoice.paid") {
// fulfil the order
}
res.sendStatus(200);
} catch (error) {
if (error instanceof SouthbillSignatureError) return res.sendStatus(400);
throw error;
}
});
Configuration
new Southbill({
apiKey: process.env.SOUTHBILL_API_KEY,
baseUrl: "https://api.southbill.com",
timeout: 30_000,
maxRetries: 2,
});
All merchant API keys are live keys (sk_live_...). Southbill has no test mode.
reports which mode the client runs in.