# Conventions

### Money is integer agorot

Every amount in every request and response is an **integer in agorot** (₪1 = 100 agorot). `35400` means ₪354.00. There are no floats anywhere. VAT rates are in **basis points**: `1800` = 18%.

### Response envelope

Success: `{"ok": true, ...payload}`. Failure: `{"error": "<message>", "reason": "<code>"}` with the matching HTTP status:

| `reason` | HTTP | Meaning |
|---|---|---|
| `not_found` | 404 | No such resource under your key |
| `validation` | 400 | Bad input (message says what) |
| `doc_type_not_allowed` | 400 | This dealer type may not issue this document type |
| `payments_mismatch` | 400 | Payments don't cover the document total |
| `not_draft` | 409 | Tried to modify/delete an issued (immutable) document |
| `conflict` | 409 | State conflict (e.g. numbering) |
| `pdf_pending` | 409 | PDF not rendered yet. Retry shortly (section 5.6) |
| `allocation_required` | 422 | Invoice over the threshold needs an allocation number (section 5.7) |
| `approval_required` | 403 | The business's account is not open: `pending` (never approved) or `suspended` (approved once, then shut by us). Issuing, expense recording and uploads are refused; the message says which. Contact us |
| `limit_reached` | 429 | A per-business ceiling hit: the monthly document/expense ceiling BillOS set, or a pending account's daily draft cap |
| `rate_limited` | 429 | Slow down; honor `Retry-After` |
| `quota_exceeded` | 429 | Daily OCR quota exhausted. Resets at midnight Asia/Jerusalem |
| `too_large` | 413 | Request body over the size limit (OCR images: 5MB) |
| `forbidden` | 403 | Key lacks the required scope |
| `unconfigured` | 503 | Service-side configuration missing |
| `internal` | 500 | Unexpected server error. Report it to us |
| `provider` | 502 | Internal dependency failed. **Transient, safe to retry** (with the same `Idempotency-Key` a retry can never double-create) |

### Idempotency

`POST .../documents` and `POST .../expenses` accept an idempotency key: either the `Idempotency-Key` header or an `externalRef` field in the body (your own stable id, e.g. your order id). Retrying the same call returns the **same** row with `"deduped": true` instead of creating a duplicate. **Always send one**, because it makes network retries and double-clicks safe. Unique per business, max 1 per document.

### Dates

Dates are `YYYY-MM-DD` strings (or ISO datetimes; only the date part is used). The service's calendar timezone is Asia/Jerusalem.