# API keys & authentication

Create keys, keep them safe, rotate them

# API keys

## Create a key

Open **Dashboard → Developers → API keys** and click **Create key**. Pick a name and copy the secret. Southbill issues isolated live and sandbox keys. Create `sk_live_…` keys under **Dashboard → Developers → API keys** and `sk_test_…` keys under **Dashboard → Developers → Sandbox**. Live secrets are shown once; sandbox secrets remain revealable and copyable in the Sandbox tab.

Keys look like:

```
sk_live_ABCDEfghi23jkLmnOPqrSTUv...   ← live\nsk_test_ABCDEfghi23jkLmnOPqrSTUv...   ← sandbox (`livemode: false`)
```

## Authenticate a request

Send the secret as a `Bearer` token in the `Authorization` header:

```http
POST /v1/checkout/sessions HTTP/1.1
Host: api.southbill.com
Authorization: Bearer sk_live_ABCDEfghi23jkLmnOPqrSTUv...
Content-Type: application/json
```

Never call the API with a **secret** key (`sk_…`) from the browser — requests carrying an `Origin` header are rejected with `401`. For client-side calls use a **publishable** key (`pk_live_…` or `pk_test_…`) restricted to allow-listed origins; it can only create Checkout Sessions from your own catalog prices.

## Scopes

Secret keys carry explicit scopes. A call outside the key's scopes returns `403 permission_error`. Publishable keys ignore scopes and are limited to the browser checkout flow.

| Scope | Grants |
|---|---|
| `checkout:write` / `checkout:read` | Create and read [Checkout Sessions](/docs/api/checkout-sessions). |
| `products:write` / `products:read` | Manage the catalog and prices. |
| `customers:write` / `customers:read` | Manage [Customers](/docs/api/customers). |
| `invoices:write` / `invoices:read` | Create, send, void and read [Invoices](/docs/api/invoices). |
| `payments:read` | Read [Payments](/docs/api/payments). |
| `refunds:write` / `refunds:read` | Issue and read [Refunds](/docs/api/refunds). |
| `subscriptions:write` / `subscriptions:read` | Manage [Subscriptions](/docs/api/subscriptions) and subscription links. |
| `events:read` / `events:write` | Read the [Events](/docs/api/events) log and replay deliveries. |
| `webhooks:write` / `webhooks:read` | Manage [webhook endpoints](/docs/api/webhook-endpoints) and read their delivery log. |
| `balance:read` | Read the [balance and ledger](/docs/api/balance). |
| `store:read` / `orders:read` / `orders:write` / `files:write` | Southbill Store catalog, orders and file uploads. |

**Payouts and bank data are never exposed to the API** — settlements are dashboard-only, by design.

## Rotation

Rotating a key is a two-step revoke:

1. Create a new key, deploy it, verify traffic uses it.
2. Revoke the old key in the dashboard (`revoked_at` is set immediately, all subsequent requests receive `401`).

## Idempotency

Every mutating request accepts an `Idempotency-Key` header. Southbill stores the first response for 24 hours and returns the exact same status and body when the same key is sent again with the **same payload**. Reusing the key with a different payload returns `409 idempotency_error` (`Idempotency-Key reused with different payload`).

```http
Idempotency-Key: order_9781_attempt_1
```

