# Authentication

Every request carries your API key in the `X-Api-Key` header:

```bash
curl -H "X-Api-Key: bk_live_..." https://api.billos.co.il/v1/businesses/BID
```

- Keys look like `bk_live_…` (production) or `bk_test_…` (the sandbox, section 10) and are shown **exactly once** when issued. We store only a hash, so if you lose the key, a new one must be issued.
- Every response carries `X-BillOS-Mode: live` or `X-BillOS-Mode: sandbox`, saying which of the two databases answered.
- **The key must live server-side only.** Call BillOS from your backend (API routes / serverless functions). Never embed the key in a mobile app or browser bundle.
- `401`: missing key, unknown key, revoked key, or expired key.
- `403 {"reason":"forbidden"}`: your key lacks the scope for that endpoint. Scopes: `businesses` (businesses + parties), `documents`, `expenses`, `export` (OPENFRMT / continuity / backup / files), and `ocr`.

> **`ocr` is the one scope you are not given by default.** Every receipt scan runs a billed AI call on our side (in the sandbox exactly as in live), so it is granted on request rather than bundled: ask from the console (מפתחות API → סריקת קבלות) and we enable it on both of your environments. Everything else is on your keys from the first minute.

### Multi-tenant model

One API key owns many **businesses**. Each business is one Israeli dealer (עוסק), one of your end users. You create a business per user (section 4), and `GET /businesses` lists every business under your key; every other endpoint is nested under `/businesses/:bid` and only works for businesses your key created. A request for another key's business returns `404` (not `403`: existence is not revealed).

### Key rotation

A client can hold several keys, up to a ceiling of **10 active keys at once** (rotation headroom, not a fleet; configurable per account if you genuinely need more). Minting and revoking are **self-service from the console** once your account is approved: sign in at [dash.billos.co.il](https://dash.billos.co.il), pass the SMS check, and issue or kill a key yourself. To rotate: mint the successor, switch your deployment to it, revoke the predecessor. Nothing else under the client moves.

`GET /keys` lists every key under your client with its prefix, label, creation time and last use, and marks the one making the request, so a key you did not create is visible to you.

Two things a key can never do to itself, by design: **mint** and **revoke**. Those live behind your console session and its SMS check, because a leaked key that could issue its own successor would survive its own revocation. `billos login` (section 13) is the same rule from the terminal: the browser approves, the key is minted there.

### Rate limit

**60 requests per minute per key** (sliding window). Exceeding it returns `429 {"reason":"rate_limited"}` with a `Retry-After` header (seconds). Back off and retry. `GET /usage?days=30` returns your own per-endpoint request and error counts, the first place to look when you are throttled or failing.

Behind that sit a few **daily backstops**, deliberately high enough that a working integration never meets them and low enough to bound a runaway loop or a leaked key. They apply to every account on every plan, and they answer `limit_reached` (429):

| Backstop | Default |
|---|---|
| Documents opened per business, per day | 300 |
| Expense rows opened per business, per day (uploads included) | 300 |
| New businesses per API key, per day | 50 |
| OCR scans per API key, per day | 200 (`quota_exceeded`) |

These are not your plan's ceilings; those are the monthly numbers on the business object (section 4). If a legitimate workload needs more of either, tell us and we raise it on your account.