# 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

```bash
npm install southbill
```

Requires Node.js 18 or newer.

## Create a checkout session

```node
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:

```node
await southbill.invoices.create(params, { idempotencyKey: `inv-${orderId}` });
```

## Pagination

```node
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`.

```node
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.

```node
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

```node
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.

