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 southbill package 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("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.