oc · docs
docs / overview

API reference

Every product and protocol in the OrangeCheck family that ships an HTTP API exposes a machine-readable OpenAPI 3.1 spec at /api/openapi on its own origin, plus an interactive /api-explorer page (Swagger UI). Session-bound endpoints use the same auth scheme name (cookieAuth) everywhere.

Currently shipped

ProductSubdomainOpenAPI specInteractive explorer
Auth hostochk.io/api/openapi/api-explorer
OC Attestattest.ochk.io/api/openapi/api-explorer
Meme.ochk.io/api/openapiinline at /me

The narrowed product pages (linked in the sidebar under this group) embed the same spec rendered inline + cross-link to the live explorer.

Errors

Every API signals failure with the HTTP status first. The JSON body is not uniform across the three hosts, so branch on the status code and treat the body as a machine-readable hint. What each one returns today:

attest.ochk.io

CaseStatusBody
Query or body fails validation400{ "error": "bad_request", "issues": [ … ] } — issues is optional
/api/check finds no proof404{ "ok": false, "reasons": ["not_found"] }
Check ran, thresholds not met200{ "ok": false, "reasons": [ … ], … }
Wrong method405{ "error": "method_not_allowed" }
Per-IP limit exceeded429{ "error": "rate_limited" } — no Retry-After header; wait a minute
Unexpected failure500{ "error": "server_error" }

/api/publish-attestation answers { "ok": false, "error": "<code>" } (missing_envelope, invalid_json, rate_limited, …).

ochk.io (auth host)

CaseStatusBody
Most failures4xx/5xx{ "ok": false, "reason": "<code>" }
No session401{ "ok": false, "reason": "not_authenticated" }
Request validation (some)400{ "error": "bad_request", "issues": [ … ] }
Per-IP limit exceeded429{ "ok": false, "reason": "rate_limited" } on most endpoints; { "error": "rate_limited" } on /api/challenge and /api/auth/switch

me.ochk.io

Handlers answer { "ok": false, "reason": "<code>" }, { "ok": false, "error": "<code>" } or { "error": "<code>" }, depending on the route; some add context fields (project_key, …). Rate limits answer 429 with { "error": "rate_limit_exceeded", "retry_after_seconds", "bucket" }, or for per-project event caps { "error": "project_rate_limit_exceeded", … } plus a Retry-After header.

What about the other subdomains?

  • pledge.ochk.io, stamp.ochk.io, vote.ochk.io, agent.ochk.io, lock.ochk.io — protocol resolver sites; the load-bearing crypto + canonicalization is in the SDKs, not in HTTP APIs. The /api/auth/me endpoint each of them exposes is a delegated session check that goes through the auth host (documented at /api-reference/auth-host).

Generating clients

Each spec is canonical OpenAPI 3.1 — works with every standard generator. Example: a Python client for the Me API:

openapi-generator-cli generate \
    -i https://me.ochk.io/api/openapi \
    -g python \
    -o ./me-client

Same recipe with -g go, -g rust, -g typescript-fetch, etc. The specs are public + CORS-permissive so you can hit them from anywhere; cached 5 minutes server-side so client-generation tools that hammer them don't poison the response.

Trust model

These OpenAPI specs are documentation, not protocol artifacts. The canonical contracts are still the TypeScript handler source + @orangecheck/* SDK conformance vectors. If a spec ever drifts from the implementation, the implementation wins — file an issue on oc-me-web / oc-www / oc-attest-web and the spec gets corrected on the next deploy.