Skip to main content
The API starts a run of a harness on a machine, reads everything that run did, and answers the questions it asks. It is the same API the Splox app is built on, so anything you can watch happen in a chat you can drive from your own code. The first call needs nothing but a key:

Base URL and versions

https://splox.io/api is the root, and every path under it carries its own version. Nothing is rewritten: the path you write is the path that is served. v2 is the contract the rest of these pages describe. It is contract-first: paths, fields, statuses and error codes come from a spec the server is built against, and every response body is JSON with snake_case fields.
Every request and response on these pages was run against a live Splox instance with SPLOX_BASE_URL pointing at it. Ids, timestamps and token counts are as they came back.

What a request looks like

A key in a header, JSON in the body:
Three rules hold everywhere:
  • Bearer only. No cookies, no query-string keys. See Authentication.
  • Writes carry an Idempotency-Key. It is required — not optional — on POST /v2/runs, POST /v2/harnesses, POST /v2/evaluations and POST /v2/interactions/{id}/responses. Repeat the request with the same key and the same body and you get the original answer back, with Idempotency-Replayed: true on it. Same key, different body, and you get 409 idempotency_key_conflict.
  • Unknown fields are refused. A typo is an error, not a silently ignored key:
A v2 request other than the event stream is given 30 seconds on the server; the stream has no such limit and stays open for the length of the run.

What an answer looks like

A single resource comes back as itself. A collection comes back as a page:
Paging is by cursor, never by offset. Pass cursor=<next_cursor> to continue and limit= to size the page (1–100, default 20; the event journal allows up to 500). A cursor is bound to the endpoint and the filters that produced it — reuse it somewhere else and the API says so rather than quietly returning the wrong rows. Anything that is not a 2xx is an RFC 9457 problem document with application/problem+json and a stable code.

Ids

Public ids are a prefix and 26 Crockford base32 characters — a UUID in a form that says what it names: /v1/... speaks raw UUIDs for the same objects. The SDKs convert both ways, and the conversion is pure — the same UUID always encodes to the same public id:
Timestamps are RFC 3339 in UTC. Money is a decimal string"0.027065", never a JSON float, because a float would round somebody’s bill.

What the SDKs add over raw HTTP

The wire is simple enough to use with curl, and the Python, Node and Go SDKs are the same wire with the tedious parts done for you:
  • an Idempotency-Key on every write, and retries that reuse it rather than duplicating work
  • cursor pagination as an iterator
  • the SSE stream reconnected with Last-Event-ID, deduplicated by event id, and closed after the terminal event
  • problem documents as typed exceptions with .code, .status_code and .trace_id
  • public-id encoding, so a raw UUID is accepted wherever an id is

Where to go next

Authentication

Where a key comes from and how it is sent.

Runs

Start one, watch it, read what it produced.

Streaming

The event journal, live or by page.

Errors

The problem shape and every code it carries.