# Sandbox: test keys

Every key is either **live** (`bk_live_…`) or **sandbox** (`bk_test_…`). The API is the same in both: same base URL, same endpoints, same request and response shapes, same error codes. What differs is where the data goes.

A sandbox key answers from a **separate BillOS database**. Businesses, parties, documents, numbers, expenses and exports you create with it exist only there: nothing done with a test key can reach a real ledger, and nothing in a real ledger is visible to a test key. Every response says which side it came from:

```
X-BillOS-Mode: sandbox
```

Check that header on your first request. A live key pasted into a test environment issues real, numbered, immutable documents, and a test key pasted into production returns `404` for every business you created in live.

### What behaves differently

| | Live | Sandbox |
|---|---|---|
| Numbering | gapless, permanent | gapless within the sandbox business; the database may be reset |
| PDFs | signed (PAdES), marked `[מקור]` / `[העתק]` | a **SANDBOX** watermark on every render, a footer note that the document is not an accounting document, and **not signed**: issue returns `warnings: ["unsigned"]` |
| Frozen snapshot | the legal record | the same shape, plus `software.sandbox: true` |
| Israel Tax Authority (allocation numbers) | requested automatically for a connected business | **never called**. An invoice over the threshold issues with the `allocation_missing` warning, or is refused with `allocation_required` when the business has `requireAllocation: true`, so both paths are testable |
| Files (PDFs, receipts, exports, backups) | object storage + off-site archive | stored in the sandbox database only, never archived |
| OCR | a billed AI call, `ocr` scope, daily cap | the same: a scan costs the same in either mode |
| Rate limit | 60 requests/min per key | the same |

Everything else (validation, totals and VAT math, idempotency, credit notes, prints, מבנה אחיד, the continuity report, backups) runs the same code and returns the same answers. If it works against the sandbox it works against live.

### Retention

Sandbox data is kept, but it is a test database: it is not backed up, it is not archived, and we may reset it (with notice). Do not use it as storage, and do not expect a sandbox business to exist in live.

### Going live

1. Get a live key. Both kinds are issued by us and shown once; there is no self-serve.
2. Replace the key. Nothing else changes: same base URL, same code.
3. Create each real business again with `POST /businesses`. Ids from the sandbox do not exist in live.
4. Confirm `X-BillOS-Mode: live` on the first response.