Everything the CLI and connectors do goes through one plain HTTPS + JSON API,
versioned under /v1/ and authenticated with a bearer token on every route.
A REST endpoint and its MCP tool twin are thin adapters over the same core, so
the two surfaces return byte-identical payloads.
The base URL is your Spor server. Hosted teams use https://api.sporhq.io;
a self-hosted deployment uses its own origin. All routes are versioned under
/v1/ (the OAuth routes used for sign-in sit at /oauth/* — see
Authentication).
Auth: send Authorization: Bearer <token> on every request. Transport
is HTTPS only. See Authentication for token kinds.
Content type: request and response bodies are JSON. Request bodies are
capped at 1 MB (413 too_large).
Path parameters (node ids, project slugs) must match
^[a-z0-9][a-z0-9-]*$.
Errors: every non-2xx response carries a
{"error": {"code", "message", "details"}} envelope. See
Errors and compatibility.
Two environment variables switch a Spor client into remote mode; unset, it
reads the local graph home directly. The legacy SUBSTRATE_* spellings are
still read (see Errors and compatibility).
SPOR_SERVER=https://api.sporhq.io # REST base (the hosted default)
SPOR_TOKEN=spor_pat_... # per-user token
SPOR_ORG=acme # select a stored tenant by org
spor join <token> writes the first two for you, defaulting SPOR_SERVER
to the hosted base; pass a URL (spor join <url> <token>) to point at a
self-hosted server instead.
Every mutation is validated, attributed, serialized, and committed to the
graph’s version history. Attribution is stamped from the authenticated token
(any author: in the payload is discarded), updates require the revision
you read (a mismatch is a 409 conflict — re-read and retry, no silent
last-write-wins), and validation failures return the validator’s error list
verbatim so a calling program can self-correct. The full contract is on
Writes.