API Reference

A public, read-only, unauthenticated API. Every endpoint below is designed to be implementable by a dumb static file server — there is no required query parameter, no server-side state, and every response is cacheable. Base URL used in these examples: https://api.circuits.siros.org.

GET /v1/manifest.json

The full catalog. Cacheable, ETag-conditional, small (a few KB at this catalog's size).

curl -sS https://api.circuits.siros.org/v1/manifest.json | jq .

Conditional revalidation — the normal client path after the first fetch (a 304 costs a few hundred bytes, not the whole document):

curl -sS -D- -o /dev/null \
  -H 'If-None-Match: "sha256-<etag-from-first-response>"' \
  https://api.circuits.siros.org/v1/manifest.json
# → HTTP/2 304, empty body

Cheap staleness check without transferring the body:

curl -sSI https://api.circuits.siros.org/v1/manifest.json | grep -i x-catalog-generated-at

GET /v1/circuits/{id}.json

A single catalog entry, by id or aliases — the bare object, not wrapped in a manifest envelope. Useful when a client already knows the id it wants and would rather not parse the whole catalog.

curl -sS https://api.circuits.siros.org/v1/circuits/longfellow-libzk-v1_8_2_4307_2945.json | jq .

Requesting an alias 301-redirects to the canonical id:

curl -sSL https://api.circuits.siros.org/v1/circuits/longfellow-8-2.json | jq -r .id

An unpublished or unknown id returns 404 with a problem+json body — the two cases are indistinguishable by design.

GET /v1/circuits?… (optional convenience — no client should depend on it)

A filtered listing, for humans and debugging. Unknown query parameters are ignored, not rejected.

curl -sS 'https://api.circuits.siros.org/v1/circuits?system=longfellow&numAttributes=2' | jq '.circuits[].id'

status defaults to active; pass status=all to include deprecated/revoked entries too.

GET /v1/artifacts/{alg}/{hex}

Content-addressed circuit bytes. {alg} is sha256 for now; {hex} is the lowercase hex digest, also given in the manifest entry's artifact.hash. The address is the integrity guarantee — verify it yourself, don't just trust the server:

HASH=9f2c1d5e4b8a37c60d1e2f4a5b6c7d8e90a1b2c3d4e5f60718293a4b5c6d7e8f
curl -sS -o circuit.zst https://api.circuits.siros.org/v1/artifacts/sha256/$HASH
sha256sum circuit.zst   # must equal $HASH

Responses are immutable and cached forever (Cache-Control: immutable) — fetch each hash at most once. Range requests are supported:

curl -sS -r 0-15 -D- -o /dev/null https://api.circuits.siros.org/v1/artifacts/sha256/$HASH
# → HTTP/2 206, Content-Range: bytes 0-15/<size>

Error responses

All non-2xx responses use application/problem+json (RFC 9457):

{
  "type":   "https://api.circuits.siros.org/problems/artifact-not-found",
  "title":  "Artifact not found",
  "status": 404,
  "detail": "No artifact with sha256:9f2c… is present in this catalog.",
  "instance": "/v1/artifacts/sha256/9f2c…"
}

Treat the HTTP status code as authoritative, the body as advisory-only. If this API is ever mirrored behind a plain static host or CDN, a miss there returns whatever that host returns for a missing key — not necessarily a parseable problem+json body.

Versioning & stability

/v1/ is the schema-version prefix. On a breaking change, /v2/ would be added while /v1/ keeps being served for at least 12 months — a mobile app silently losing its ability to fetch circuits is a bad failure mode we design against. Additive changes (a new optional field, a new system value) never bump the version; clients are expected to ignore fields and systems they don't recognise.

Generated API reference (OpenAPI/Swagger): api.circuits.siros.org/swagger.