RRecords Labs Help Center

Rate limits, errors and the stability policy

Rate limits

  • Requests are budgeted per key and per org, per minute; the tighter bucket wins.

  • Every API-key response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. An exhausted budget returns 429 with a Retry-After header.

  • A separate daily spend guardrail also returns 429 when the organization's cost cap is exceeded.

Errors

Errors use the envelope {"detail": ...} (body-validation errors return a list of field errors). Every response carries an X-Request-ID header — quote it in support requests and the exact call can be traced.

Status

Trigger

401

Missing / invalid / expired / revoked API key

403

Key missing the required scope; an org key on a personal-only endpoint (or vice versa); or the agent isn't API-enabled

404

Document / Creation / agent / conversation not found (or not accessible)

422

Invalid request body (missing field, bad enum value)

429

Rate limit exhausted, or the organization's daily spend guardrail exceeded

502

Upstream retrieval/model failure (the raw cause is never echoed)

503

A dependency is not configured on the server

Match on status codes, never on message strings — messages may be reworded at any time.

Stability policy

The public developer API is the stable contract for third-party integrations: scripts, Zapier/n8n/Make automations, the browser extension, MCP-adjacent tooling, and anything a customer builds against an sk-live-… API key. It lives under /api/v1 (backend/app/api/routes/v1_* + the automation subtree), authenticated with API keys.

It is distinct from /api/client/v1, the JWT-authenticated first-party client surface (client-api-policy.md). The two share service-layer code; they never share handlers by accident.

The compatibility promise

Code written against /api/v1 today keeps working. Concretely:

  1. Additive-only. New fields, new endpoints, new optional parameters, new enum values: fine, at any time, without notice. Removing or renaming fields/endpoints, changing types or semantics, tightening validation on existing inputs, narrowing a scope an endpoint accepts: breaking — these require a new versioned path (/api/v2/... for the affected resource) and a deprecation window of 12 months on the v1 spelling.

  2. Alias windows. When a request-field spelling is unified (e.g. effort/mode joining answer_effort/answer_mode on the per-agent answer endpoint), the old spelling is kept as a permanent alias — aliases on this surface do not expire.

  3. Tolerant readers expected. Clients must ignore unknown response fields; new fields appear without a version bump. The server never starts requiring a new request field from existing callers.

  4. Scopes only widen. An endpoint may start accepting additional scopes or key types (e.g. GET /v1/agents accepting retrieve as well as answer); it never drops one it accepted.

  5. Deprecation process. A deprecated endpoint or field is (a) marked in the changelog and the OpenAPI description, (b) kept fully functional through the window above, and (c) announced through the discovery document (GET /api/v1) before removal. Nothing is removed silently.

Error contract

  • Errors use the FastAPI envelope {"detail": ...}; status codes and their triggers are documented in api-v1-reference.md.

  • Every response carries an X-Request-ID header for tracing; quote it in support requests.

  • The first-party client error-code registry (ClientErrorCode in shared/types/python.py) applies to /api/client/v1, not this surface; /api/v1 errors are matched on status code, never on message strings (messages may be reworded at any time).

Rate limits

  • Requests are budgeted per key and per org, per minute; the tighter bucket wins. Limits are org-configurable server settings.

  • Every API-key response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers. An exhausted budget returns 429 with Retry-After.

  • A separate daily spend guardrail also returns 429 when the org's cost cap is exceeded.

Contract visibility

  • The reviewable public contract is the committed docs/v1-openapi.json, exported by scripts/export-v1-openapi.py from the same build (app.core.openapi_export.build_v1_spec) that serves GET /api/v1/openapi.json. A drift test (test_v1_openapi_committed.py) fails CI when the committed spec is stale, so every contract change is visible in the PR diff.

  • GET /api/v1 (the discovery document) lists every top-level endpoint with its scope + key type and is drift-tested against the live route table (test_v1_meta.py).

  • Human-readable docs: api-v1-reference.md, the generated Help Center articles under developer-help-center/, and the served Swagger UI at GET /api/v1/docs.

Changelog

Additions and deprecations are recorded per release in api-v1-changelog.md.

Was this article helpful?
Related articles
API changelogDevelopersAuthentication, keys and scopesDevelopersBrowser extensionDevelopersDesktop sync and ObsidianDevelopers