API documentation
/api/v1 — using docs/backend-api-contract.md as the reference. Request snippets use the shared builders; response shapes illustrate the contract, not live data.- Base URL
https://sheet.zaber.tech/api/v1- Authentication
Authorization: Bearer sz_live_…- Success envelope
{ data, meta }- Every refusal
{ error: { code, message, category } }- Documented defaults
- 1000 requests/hour and 10000/day per key
- Request body ceiling
- 1 MB — larger is 413
- Page size ceiling
- limit ≤ 1000
- Access
- Private platform; an invitation code, then Google sign-in
1.1At a glance
docs/backend-api-contract.md §1, §1.1, §1.2
Four facts carry the whole surface. Everything later in these pages is a consequence of them, which is why they come first and in their own plates.
https://sheet.zaber.tech/api/v1
Authorization: Bearer sz_live_<32 hex>
- One API id is one tab.
{api}in every path isapi_configurations.id— a uuid, unguessable, assigned when the API is created. The header row you designate is the row the record keys come from, and data rows start immediately below it. - A key is a bearer token, not a login. It must be unrevoked, unexpired, owned by the same user as the API, scope-compatible with the verb, and — if it carries a restriction — allowed to reach that API. Missing or invalid is 401; a scope or restriction violation is 403.
- Success is always { data, meta }.
dataholds the array, the single record, or the write counter;metacarriesapi_id,count,limit,offsetandduration_ms. - Refusal is always one shape. Every non-2xx response is
{ error: { code, message, category } }, so your error handling is a switch onerror.code, not a parser of prose. The category set isauth,rate_limit,validation,google,not_foundandinternal.
1.2What invitation-only means here
docs/plan.md D5, D11, D12 · docs/authentication-flow.md §1, §4
There is no signup form. An account exists only once a Google identity has been verified and a code the operator issued has been redeemed, and the code is stored as a SHA-256 hash with a use limit, an optional expiry and revocation. The platform has one operator: the single account holding the owner role, granted only to the configured owner email at first sign-in.
For an API consumer, that has three practical consequences, and none of them is a marketing sentence:
- Your endpoints are not public by default. Anyone who reaches
/api/v1/{api}without a valid key gets a 401 — and an id belonging to another user gets the same 404 as an id that does not exist (§1.1, docs/security.md §3), so the uuid space cannot be enumerated for content. - Documentation is public, data is not. These pages are readable without a session; the API they describe is not, and the dashboard that issues keys sits behind the invitation step.
- There is no self-service rate-limit negotiation. The limits in §1.4 are the documented platform defaults, surfaced per key in the dashboard; the only documented knob is a per-API hourly override, and owner-level settings have no storage yet.
1.3Sections
the /docs routes that exist today
Read in order for a first call, or jump to the one you need. Each page is a route of its own, and the rail on the left always shows which one you are on.
- 03AuthenticationThe Authorization header, scopes, restrictions, and why a key is shown once.
- 04Response envelope{ data, meta } on success, one { error } shape on every non-2xx.
- 05OperationsOne subsection per verb: parameters, success shape, realistic failures, an example.
- 06Error referenceEvery documented code, the status it is answered with, and what the caller should do.
- 07Rate limitsThe documented defaults, the per-API override, and the ceilings next to them.
1.4How to read the examples
docs/backend-api-contract.md §3 · src/lib/snippets.ts
§3 of the contract requires /docs to render examples generated from the spec's tested behaviour using the shared snippet builders. That is what every cURL/JavaScript/Python plate in these pages is: a real SnippetRequest passed to SnippetTabs, built by src/lib/snippets.ts — the same pure functions the playground uses. The builders validate request structure, not sheet headers, credentials or live engine behaviour; sharing them does not replace contract verification.
- Placeholders are literal.
<api-id>,<record>andsz_live_…stand for your values. Nothing on these pages is a live credential or a captured response. - Response plates use angle brackets for values too (
"count": <rows returned>) where the contract gives a field but no number. - Query strings are serialized exactly as
application/x-www-form-urlencoded— a space becomes+, a repeated key repeats (sort=-created_at&sort=id), and a comma infieldsappears as%2C, which the server decodes back. That is the shipped builder's behaviour, not a typo. - A contract change obliges the same commit to update these pages and the engine tests. If you find a page and a real response disagree, the page is the bug — report it.
1.5Status of this documentation
docs/backend-api-contract.md §4.10 · docs/integration-status.md (Measured vs asserted)
Two kinds of honesty belong on a docs landing page: what the platform does not do yet, and how much of it has been executed rather than written down.
The surfaces documented here are also the surfaces the playground exercises: /api/internal/playground calls the same engine in process, keyed by the key's row id rather than a plaintext, so a rule the playground can bend is a rule a real client can break too.
1.6Elsewhere on this site
the public pages and the dashboard they lead to