# 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, a mode (**Test** or **Live**), and copy the secret. The secret is shown **once** — Southbill stores only a SHA-256 hash. If you lose it, revoke and create a new one.

Keys look like:

```
sk_live_ABCDEfghi23jkLmnOPqrSTUv...   ← live
sk_test_ABCDEfghi23jkLmnOPqrSTUv...   ← test
```

## 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_test_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_…` / `pk_test_…`) restricted to allow-listed origins; it can only create Checkout Sessions from your own catalog prices.

## Scopes

Secret keys carry explicit scopes (`checkout:write`, `checkout:read`, `refunds:write`, `products:write`, …). A call outside the key's scopes returns `403 permission_error`. Publishable keys ignore scopes and are limited to the browser checkout flow.

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

