Errors & rate limits
Status codes, quotas and the read-path controls that bound every response.
Errors & rate limits
Status codes
| Code | Meaning | Handling |
|---|---|---|
200 |
success | — |
400 |
malformed request | fix the payload |
401 |
missing/invalid key | check Authorization |
403 |
key valid but not permitted (scope or permissions) | request the scope; the row/action is out of your entity's reach |
404 |
not found, or filtered out | a row you may not see returns 404, not 403 |
409 |
conflict (e.g. duplicate wine match) | resolve, then retry |
429 |
rate or record quota exhausted | back off; honour Retry-After |
5xx |
transient | retry with exponential backoff |
Two limits, not one
| Limit | Unit | Purpose |
|---|---|---|
| request rate | requests / window | smooths burst traffic |
| record quota | rows returned / period | stops page-walking the wine/offer tables |
Both are per entity. A 429 never reveals whether more rows exist — an exhausted quota is not a signal that
there is data behind it.
Read-path controls at a glance
Every read passes four controls before serialisation:
| Control | What it does |
|---|---|
| C1 row/field filter | removes rows failing network_shareable, permissions, or channel/tenant scope |
| C2 bounded pagination | page_size max 200; single-use cursors; read:network for the whole-network read |
| C3 per-key record quota | caps total rows returned per period |
| C4 audit & anomaly | logs every read; alerts on abnormal volume |
Full normative detail: Data-exposure controls.
Recommended client behaviour
on 429: wait Retry-After seconds, then resume from the last cursor (do not restart the walk)
on 403: do not retry — request the scope or accept the row is out of reach
on 404 for a filtered row: treat as absent (it is intentionally indistinguishable from "does not exist")