Base URL
/api/v1. Substitute the base URL from your onboarding if you have one.
Authentication
Every request carries a bearer token in theAuthorization header:
ish_sk_live_), minted in Settings, then Developers. Keys are minted with sessions:run, sessions:read, and tasks:read; ask for tasks:write, environments:read, or environments:write if the key manages a registry rather than just running against it. An ish user access token also works on the same header for personal scripts. See authentication.
What “session” means here
A session is one participant working toward one task in your environment, turn by turn. It is not the ish product’s notion of a study session (a person sitting down with a study), and it is unrelated to a browser session. Sessions live under/v1/sessions.
The operations
Twenty-one operations across four surfaces, and this is all of them. Sessions is the loop: open a session for a person, submit turns, read the trace, list your sessions, close it. The other three are registries you write once and reference by id. Environments names a target instead of describing it inline on every session. Environment versions are the declared variants of one environment, so a session can pin the exact variant it ran against. Tasks names an intent a session can bind by id, freezing its instructions and revision onto the session. You need none of the registries to run a session. Describe the environment inline, pass the instructions inline, and the sessions surface alone is a complete integration.Sessions
Environments
Environment versions
Tasks
Operations that create a thing in a workspace, or list what it owns, nest under
/workspaces/{workspace_id}/…. The rest act on an existing record by its globally-unique id, so the path carries no workspace: the id already resolves it. Both address the same workspace and authorize the same way.
Environments
An environment is your own product surface under test: the site, app, device, or world you are building. It is not a deploy target, a hosting environment, or a sandbox ish runs for you. You render it and you execute in it. Every session names the environment it runs in, one of two ways, and you must supply exactly one:environment_id, a registered environment. It supplies the default operating notes for the resolver and a default action vocabulary, and its name and kind are snapshotted onto the session.environment, an ad-hoc descriptor ({ name, kind }) described inline on the session.
kind (web, device, world today; treat it as an open union) and a config validated per kind: web needs config.url, device needs config.app_artifact, and any kind may declare an origins allowlist. Identity is the environment_id, never the URL, so a target reached through a rotating tunnel host keeps the same environment across sessions.
Renaming or deleting an environment never rewrites history: a session keeps the name and kind it was opened with, and its environment_id simply becomes null.
The turn-by-turn contract that drives these (ordering, retries, indexing) is in run the session loop.
Response conventions
- Correlation id. Every response carries an
X-Request-Idheader. Error bodies echo it asrequest_id. Quote it in support requests. - Two error envelopes. A request-shape failure (HTTP 422) uses the
ValidationErrorenvelope, a field-level object witherror_codeand anerrorsarray so you can pinpoint the offending field. Everything else (401, 403, 404, 409, 502, and handler-raised 422s) uses theErrorenvelope, a{ detail, request_id }object wheredetailmay be a string or a structured object carrying a machine-readableerror_kindsuch asidempotency_conflict,turn_index_mismatch, ordecision_invalid. Every kind, with what it means and what to do, is in the error reference; where each one lands in the loop is in handling errors. - Open unions. Several enum-typed and block-typed fields (
sentiment,session_status,resolution, the observation blocktype) may gain new values over time. Tolerate a value you do not recognize rather than failing on it. - Idempotency. Every create accepts an
Idempotency-Keyheader (sessions, environments, environment versions, tasks); a retry with the same key and body replays the thing already created. See the create operations and run the session loop. - Pagination, two shapes. Reading one session pages its trace by index: pass
after_indexandlimit(default 50, max 200), and page again whilehas_moreis true. Listing a workspace’s sessions pages by opaque keyset instead: passafterandlimit(default 25, max 100), then follownext_cursorwhilehas_moreis true, newest first. Never build a cursor yourself and never treat it as an offset. The environment, environment-version, and task lists return the whole collection underitemsand are unpaginated today; they carryhas_more: falseandnext_cursor: nullso pagination can land later without a wire break, so read those two fields rather than assuming one page forever. - Versioned path. Every path is versioned under
/api/v1. What that promises, and what may change inside it, is in versioning.
Before you integrate
Quickstart
Run one turn end to end against the live wire.
Run the session loop
The full contract: ordering, retries, errors, pagination.
Observations
What a turn may send, and why state is refused.
Author your environment
Declare actions and render frames that decode.