Sheet Zaber · Reference

/api/v1 documentation

The contract in docs/backend-api-contract.md §1, rendered from the same snippet builders the playground uses. Private platform, public documentation — no signup on these pages.

Docs · 01 Overview

API documentation

Sheet Zaber turns one tab of one Google spreadsheet into one HTTP endpoint that you read and write with a Bearer key, using the spreadsheet owner's own Google grant underneath. These pages document that public surface — /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.

Where the API lives
https://sheet.zaber.tech/api/v1
How you authorise
Authorization: Bearer sz_live_<32 hex>
  • One API id is one tab. {api} in every path is api_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 }. data holds the array, the single record, or the write counter; meta carries api_id, count, limit, offset and duration_ms.
  • Refusal is always one shape. Every non-2xx response is { error: { code, message, category } } , so your error handling is a switch on error.code, not a parser of prose. The category set is auth, rate_limit, validation, google, not_found and internal.

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

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> and sz_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 in fields appears 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

Landing
/
Sign in
/login
API keys
/keys
Playground
/playground
Legal
/privacy and /terms