Sessions
Persistent sandboxes that survive across agent tool calls.
Sessions are the primary primitive for agents. Create once, call exec/files/expose many times, destroy when done.
All requests require Authorization: Bearer inis_... and Content-Type: application/json. Path parameter {id} is the session ID.
Prefer the CLI (inis sessions, inis exec --session) or an SDK for day-to-day use.
Create
Request body
{
"size": "medium",
"volume_id": "vol_...",
"max_lifetime_ms": 3600000,
"idle_timeout_ms": 300000,
"on_detach": "pause",
"paused_ttl_ms": 86400000
}| Field | Required | Description |
|---|---|---|
size | no | small (default), medium, or large |
volume_id | no | Attach a persistent volume |
max_lifetime_ms | no | Hard cap on session lifetime |
idle_timeout_ms | no | Auto-pause after idle period |
on_detach | no | What to do when the last client detaches: pause (default), keep_live, or destroy |
paused_ttl_ms | no | Auto-destroy a paused session after this long. Omit/0 for the server default; negative for never |
Response 201
{
"session_id": "2476b0a6-722e-4bd9-9f25-771ccbdd53bd",
"state": "live",
"created_at": "2026-06-22T13:46:00Z"
}Get
Response 200 — session metadata (session_id, state, volume_id, created_at, on_detach, paused_ttl_ms).
List
List your sessions, newest first. Filter with ?state= (live, paused, creating, or ended) and paginate with ?limit= and ?cursor=.
state=ended returns the history of destroyed sessions — terminal rows that carry ended_at and end_reason (client_destroy, shell_exit, on_detach_destroy, max_lifetime, paused_ttl, or error). History is metadata only; the session's disk and snapshot are already gone.
Destroy
Optionally pass ?reason= (client_destroy — the default — or shell_exit) to record why the session ended on its history row.
Response 204 — empty body.
Exec
Request body
{
"command": ["python3", "-c", "print(42)"],
"cwd": "/workspace",
"timeout_ms": 30000
}Response 200
{
"stdout": "42\n",
"stderr": "",
"exit_code": 0,
"duration_ms": 41,
"timed_out": false,
"sandbox_id": "c0ea18af-3c3e-4491-8f17-5b7a8d4a65a6"
}Files
Single endpoint; set op to read, write, or list.
Write
{
"op": "write",
"path": "/workspace/out.txt",
"content": "hello"
}Read
{
"op": "read",
"path": "/workspace/out.txt"
}Response includes "content": "hello".
List
{
"op": "list",
"path": "/workspace"
}Response includes "entries": ["out.txt", "data.csv"].
Expose
Start an HTTPS preview URL for a port inside the guest. The process must bind to 0.0.0.0, not 127.0.0.1.
Request body
{
"port": 8080,
"visibility": "token",
"auth": "bearer"
}auth controls access to the preview URL: none (default) leaves it open, bearer requires every inbound request to carry an Authorization: Bearer <auth_token> header.
Response 200
{
"session_id": "2476b0a6-722e-4bd9-9f25-771ccbdd53bd",
"port": 8080,
"preview_url": "https://8080-2476b0a6-722e-4bd9-9f25-771ccbdd53bd.ams1.sb.inis.run",
"guest_ip": "10.42.3.2",
"auth": "bearer",
"auth_token": "qN3kf2..."
}When auth is bearer, auth_token is returned once here and never again — store it. Inbound requests without a matching Authorization: Bearer header are rejected with 401. The active mode shows up as auth on each entry in exposed_previews from a session fetch, but the token itself is never re-surfaced.
Preview URLs follow https://{port}-{session_id}.{node-domain}.
Pause and resume
Pause stops billing for compute; storage for the snapshot continues. Any exec/files/expose call on a paused session wakes it automatically, as does attaching with inis ssh.
Pause also happens on its own: when the last client detaches (if the session's on_detach is pause, the default) and after the idle_timeout_ms window. A paused session is auto-destroyed once it sits past its paused_ttl_ms.
Fork
Clone a live session into N independent children — useful for parallel eval or RL rollouts.
Request body
{
"count": 10
}Response 200
{
"parent_session_id": "2476b0a6-722e-4bd9-9f25-771ccbdd53bd",
"children": ["...", "..."]
}Checkpoints
A checkpoint is a named, retained snapshot of a live session. It survives the session's destruction and is deleted only when you ask. See Concepts for checkpoint vs fork vs pause.
Capture a checkpoint. The source session keeps running.
Request body
{
"name": "clean"
}Response 200
{
"checkpoint_id": "ckpt_3f9a...",
"parent_session_id": "...",
"name": "clean",
"size_bytes": 268435456,
"created_at": "2026-06-23T10:00:00Z"
}List checkpoints captured from a session.
Fetch a checkpoint's metadata.
Delete a checkpoint and free its disk.
Restore in place
Roll a session back to a checkpoint, reusing the same session ID. The "run untrusted code, then roll back to clean" flow.
Request body
{
"checkpoint_id": "ckpt_3f9a..."
}New session from a checkpoint
Start a fresh, independent session from a checkpoint (the template path). You can also pass from_checkpoint to POST /v1/sessions.
Lifecycle
creating → live ⇄ paused → destroyed → (ended history)
↑ ↓
wake-on-op auto-pause on detach / idlelive → paused happens on detach (on_detach: pause) or idle timeout; paused → live on any operation or attach. A session reaches destroyed explicitly, at max_lifetime, or when a paused session passes its paused_ttl — and leaves an ended history row behind either way.
See Concepts for when to use sessions vs stateless execute.