Skip to content

api overview

The spirby api is a hand-designed rest surface — resource urls, standard http methods, standard status codes. No graphql, no rpc, no auto-generated wrapper around an internal contract.

  • base url: https://api.spirby.com
  • versioning: /v1/*. additive changes only inside v1; breaking changes get a new prefix.
  • auth: bearer api keys, two scopes (read and read:write). see authentication.
  • rate limits: per-key budget, surfaced on every response via x-ratelimit-* headers.
  • webhooks: signed outbound deliveries for post.*, vote.*, comment.*, and changelog.* events. see webhooks.
  • machine-readable spec: openapi.json — generated from the same zod schemas the handlers validate with, so it never drifts.
  • browseable reference: /api/reference — every endpoint with try-it.

All responses use one of three shapes. Single-resource and collection envelopes are always { data } so clients only have one parser to write.

// success — single resource
{ "data": { "id": "...", ... } }
// success — collection (cursor pagination)
{ "data": [ ... ], "nextCursor": "..." }
// error
{ "error": { "code": "ERR_NOT_FOUND", "message": "post not found" } }

Error details is omitted when empty. code is machine-readable and stable for the v1 lifetime; render your own copy from it. message is plain English suitable for logs.

codehttpwhen
ERR_VALIDATION422zod validation failed on params, query, or body
ERR_BAD_REQUEST400malformed input that survived zod (e.g. bad cursor)
ERR_UNAUTHORIZED401missing, malformed, revoked, or expired api key
ERR_SCOPE_INSUFFICIENT403key lacks the required scope (writes against a read key)
ERR_FORBIDDEN403authorized but not allowed (e.g. trial-tier write while readonly)
ERR_NOT_FOUND404resource missing or not in your org (never confirms cross-org existence)
ERR_CONFLICT409slug collision, idempotency replay, already-voted
ERR_RATE_LIMITED429per-key budget exhausted; Retry-After header set
ERR_INTERNAL500unhandled error; details omitted in production

Adding new codes is non-breaking; renaming or removing one is.