---
title: "Start a session"
method: POST
path: "/o/{org}/sessions"
tags: ["Sessions"]
---

# Start a session

`POST /o/{org}/sessions`

## Request

- Base URL: `https://api.prix.dev`
- URL: `https://api.prix.dev/o/{org}/sessions`
- Auth: HTTP bearer

Starts one agent run in a fresh sandbox and returns it at once with
`202`; follow it with `GET …/events` or the key's webhook. It runs in the
repository a `resources` URL names, or in none.

Started with an API key, the run uses the key creator's own accounts, as
their console run would: a subscription first, then an API key, or the one
`account_id` names. `strategy: platform` runs it on Rush's models instead,
metered on the creator's plan. A key may have `max_concurrent` runs
in progress (default 4); one more is `429 RATE_LIMITED`. When `agent`
is a saved agent's id the run uses that saved agent, and gets exactly the connections it names
plus those the run names in `connections`. A key run's repository is
reached through its creator's GitHub App installations, and a Linear
issue through its creator's Linear connection.

## Headers

- `Idempotency-Key` string

## Request body

- SessionCreate: `agent` is required, and the repository, if any, is a `resources` URL. Any other field is `400 UNKNOWN_FIELD`; `name`, `metadata`, `output_schema`, `harness`, `agent_id` and `profile_id` are `400 FIELD_REMOVED`.
  - `agent` string: What runs: a harness (`claude`, `codex` or `opencode`), or a saved agent's id (`GET /o/{org}/agents`), which brings its harness, model, effort, instructions, skills and connections.
  - `input` union, required: The task, as a string or as content blocks. Text blocks are joined, with a blank line between them, into the prompt (at most 256 KiB, at least one text block). Every file block is stored before the run starts and downloaded into the sandbox at `/workspace/.rush/attachments/`, where the prompt names it.
    - string
    - InputBlock[]
      - union
        - object
          - `type` 'text', required
          - `text` string, required
        - object
          - `type` 'image' | 'document' | 'file', required: What the file is. `image` must be an `image/*` type; `document` and `file` take any type.
          - `name` string: The file name in the sandbox. No `/`, `\`, `..`, leading `.`, or control characters. Default: the URL's last segment, else `input-<n>`, given the extension its `Content-Type` reads as when it has none.
          - `source` union, required: Where the bytes come from. `url`: a public https file Rush fetches (public addresses only, at most 3 redirects, 60 seconds, no size limit). `base64`: the bytes in the request, which is limited to 32 MB in all. `file`: an id from `POST /o/{org}/files`, for a large private file; each id rides on one run.
            - object
              - …
            - object
              - …
            - object
              - …
  - `model` string: A model `id` that GET /o/{org}/agents/available lists for this harness. Omitted: the harness default.
  - `effort` 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto': Reasoning effort; must be one the model's row lists.
  - `account_id` string: Run on this one of the caller's own accounts (a Claude or ChatGPT subscription, or an Anthropic or OpenAI API key). Omitted: their subscriptions first, then their API key.
  - `strategy` 'platform': Run on Rush's models, metered on the caller's plan, instead of their own accounts.
  - `skills` SkillUrl[]: Skills the agent loads for this run, each by public URL, as a string or `{url}`: a GitHub `tree` URL to a directory holding `SKILL.md`, a URL to a `SKILL.md` file (`github.com/…/blob/…`, `raw.githubusercontent.com/…` or any https host), or a `.zip` URL. Fetched when the run is created; a GitHub source is pinned to the commit its branch or tag points at, and the pin is kept with the run. All of a run's skills pack to at most 96 KiB compressed. An unreachable URL is `422 SKILL_FETCH_FAILED`; no `SKILL.md`, a bad name or too large is `422 SKILL_INVALID`.
    - union: A skill by public URL, as a string or `{url}`.
      - string, uri
      - object
        - `url` string, uri, required
  - `connections` union[]: What this run connects to, each entry in one of three forms: - **An id** of one of the caller's own connections (`GET /me/connections`): an MCP server (connected with a token, by OAuth, or with no auth), a Google or Microsoft product (Gmail, Outlook, OneDrive, ...) of one account, or a GitLab account. Secrets are never named: a session gets every secret of its Project (`/o/{org}/secrets`). - **A name** of one of them, the `name` `GET /me/connections` lists: the name the caller gave an MCP server (`"deepwiki"`, `"EXA_API_KEY"`), or the provider of an account or a built-in connector, which `GET /me/connections` lists as `{type: "app", name: "linear"}` (`"linear"`, `"gmail"`). Only the caller's own rows match, and only user-level ones or ones in this run's Project. A name that matches two of them is `422 CONNECTION_AMBIGUOUS`, whose message lists their ids; send one id instead. - **An inline MCP server** `{url, name?, auth?}`, used by this run and its follow-ups only and never added to `/me/connections`. `url` is a streamable HTTP endpoint on https whose host resolves to public addresses only (else `422 MCP_SERVER_URL_INVALID`). `auth` is the shape `POST /me/connections` takes: `{mode: "bearer", token}` sends the token as `Authorization: Bearer`; `{mode: "none"}` or no `auth` sends none. A `token` beside `url` is `400 FIELD_REMOVED`. The token is stored encrypted on the run and never returned. `name` defaults to a slug of the host (`mcp-deepwiki-com`), and may not be a built-in connection's or share a name with another entry (`422 CONNECTION_AMBIGUOUS` when it matches a named server). Ids and names fit Anthropic's stored-credential model (a vault id per run); the inline form fits OpenAI's inline `authorization` and Cursor's `mcpServers` headers. An id or name that is unknown, still connecting, or waiting on a reconnect is `422 CONNECTION_NOT_READY`. Follow-ups keep all three.
    - union
      - string: A connection id or name.
      - object
        - `url` string, uri, required
        - `name` string
        - `auth` union
          - object
            - `mode` 'none', required
          - object
            - `mode` 'bearer', required
            - `token` string, required
  - `resources` object[]: What Rush puts in front of the agent before it starts, each by URL, with `connection` naming the account that reaches it when more than one could: `https://github.com/<owner>/<repo>` clones the repository at its default branch, `…/tree/<branch>` at that branch, and `…/pull/<n>` on that open pull request's branch; at most one repository per run, reached through a GitHub App installation of the caller (`connection` is an installation id from `GET /o/{org}/github`). On a Project run it may only name the Project's repository. `https://linear.app/<workspace>/issue/<ID>` puts the issue in the prompt, read through the caller's Linear connection. Any other URL is `422 RESOURCE_UNSUPPORTED`; a repository no installation covers, or an issue with no Linear connection, is `422 RESOURCE_NOT_ACCESSIBLE`.
    - `url` string, uri, required
    - `connection` string

## Response `202`

The session as `GET` reads it, in its status at admission (`queued`, `allocating` or `running`).

- CloudRunSession: A session as `GET …/sessions/{session}` and the session list return it. It starts with where the session lives, so its path is `/o/{org_id}/sessions/{execution_id}`; `project_id` appears only for a session the console ran in a Project. A field appears only when it has a value, and every time is RFC 3339 UTC with milliseconds. A create, a cancel and a follow-up answer it too. It has no `prompt`: the caller has its input, and `/messages` has every turn.
  - `execution_id` string, required: The session id.
  - `org_id` string, required: The org as the request's path named it.
  - `project_id` string, uuid: The Project the console ran the session in.
  - `status` 'queued' | 'allocating' | 'running' | 'paused' | 'input_required' | 'needs_review' | 'completed' | 'failed' | 'cancelling' | 'cancelled' | 'expired', required: `paused` is a resumable session parked between turns; `needs_review` finished without the proof it was asked for; `cancelling` appears only in the `202` answer to a cancel whose sandbox is still being released; `GET` reads `cancelled` once it is.
  - `harness` string: `claude`, `codex` or `opencode`.
  - `agent_id` string, uuid: The saved agent the session was started from, if any.
  - `model` string
  - `effort` string
  - `result` string: The agent's final answer for the last finished turn, in full.
  - `error` object
    - `code` string, required
    - `message` string, required
  - `repo_owner` string
  - `repo_name` string
  - `branch` string
  - `pr_url` string
  - `input_tokens` integer
  - `output_tokens` integer
  - `cache_read_tokens` integer
  - `cache_write_tokens` integer
  - `total_tokens` integer: Uncached input plus cache writes plus output.
  - `reasoning_tokens` integer
  - `total_cost_usd` number
  - `tool_calls_count` integer
  - `turns_count` integer
  - `artifacts` object[]: Every file the agent saved to `/workspace/.rush/artifacts/`. `url` downloads it from this API with no credential until `url_expires_at`, an hour after the read; read the session again for a fresh link. `GET …/artifacts/{name}` with the key also downloads it.
    - `name` string, required
    - `mime_type` string, required
    - `url` string, uri, required: A signed https link to the file on this API.
    - `url_expires_at` string, date-time, required
  - `attachments` object[]: The files the session was started or followed up with. `url` downloads one with no credential until `url_expires_at`, as for artifacts; `GET …/attachments/{id}` with the key also downloads it.
    - `id` string, uuid, required
    - `name` string, required
    - `mime_type` string, required
    - `url` string, uri, required: A signed https link to the file on this API.
    - `url_expires_at` string, date-time, required
  - `created_at` string, date-time
  - `completed_at` string, date-time

## Other responses

- `400`: The body is invalid: no `input` or no text block in it, a malformed input block, no `agent`, an unknown `effort`, `speed` or `persistence`, a malformed `skills`, `connections` or `resources` entry, or two repositories. A field this route does not take is `UNKNOWN_FIELD`. A `base64` file whose bytes are not its `media_type`, or an `image` block whose file is not an image, is `INVALID_BODY`. A body that still sends a removed field is `FIELD_REMOVED`, whose message names its replacement: `prompt` and `attachments` became `input`; `repos`, `installation_id`, `repo_owner`, `repo_name`, `base_branch`, `on_pr` and `sources` became `resources`; `mcp_servers` became an inline `{url, name?, auth?}` entry in `connections`, whose own `token` became `auth: {mode: bearer, token}`; `harness`, `agent_id` and `profile_id` became `agent`; `agents_repo` became a Project Skill or `skills`; `name`, `metadata` and `output_schema` are not taken.
- `401`: No bearer, an unknown, revoked or expired one, or an API key on a route keys cannot call.
- `402`: The plan does not cover this run: `TOKEN_LIMIT_REACHED` (the one-time $1 of models Rush covers is used; connect your own account), `COMPUTE_LIMIT_REACHED`, `WEEKLY_COMPUTE_LIMIT_REACHED`, `SPEND_CAP_REACHED` or `PAYMENT_METHOD_REQUIRED`.
- `403`: The Project's repository is not in a GitHub App installation linked to the caller (`INSTALLATION_NOT_LINKED`, `REPO_NOT_IN_INSTALLATION`).
- `404`: The Project, or a `file_id` in `input`, is not found (`ATTACHMENT_NOT_FOUND`).
- `409`: The Idempotency-Key was first sent with a different body or Project (`IDEMPOTENCY_CONFLICT`), the repository's GitHub App installation is suspended, a pull-request resource names one that is not open, a saved agent's catalog changed since it was reviewed (`CATALOG_REFRESH_REQUIRED`), a `file_id` already belongs to another run (`ATTACHMENT_IN_USE`), or a `file_id` was never `PUT` to its `upload_url` (`ATTACHMENT_NOT_UPLOADED`).
- `410`: A `file_id`'s stored bytes have expired (`ATTACHMENT_EXPIRED`).
- `413`: The request body is over 32 MB (`REQUEST_TOO_LARGE`). Send a large file as a `url` source, or upload it with `POST /o/{org}/files` and send a `file` source.
- `422`: A field the run cannot honor: an agent outside `claude`, `codex`, `opencode` (`UNSUPPORTED_AGENT`); a `model` the harness does not list in `GET /o/{org}/agents/available` (`code` `MODEL_UNSUPPORTED`); a `url` source that could not be fetched (`INPUT_FETCH_FAILED`: not https, a private address, more than 3 redirects, a non-2xx answer, more than 60 seconds, or an `image` block answered with something else); a skill URL that cannot be fetched (`SKILL_FETCH_FAILED`) or holds no valid `SKILL.md` (`SKILL_INVALID`); a connection id or name that is not one of the caller's connected connections, or a GitLab account (`CONNECTION_NOT_READY`); a name that matches two of them, or an inline server named like a named one (`CONNECTION_AMBIGUOUS`); an inline MCP server whose host is not public (`MCP_SERVER_URL_INVALID`); a resource URL Rush cannot attach (`RESOURCE_UNSUPPORTED`); or a repository no GitHub App installation of the caller covers, or a Linear issue with no Linear connection to read it (`RESOURCE_NOT_ACCESSIBLE`). The run is not created.
- `429`: The API key already has `max_concurrent` runs in progress (`RATE_LIMITED`).

---

[API](https://skmtc.dev/getrush/apis/rush-api.md) · [All operations](https://skmtc.dev/getrush/apis/rush-api/llms.txt) · [OpenAPI document](https://skmtc.dev/getrush/apis/rush-api/revisions/e351f947926b?raw)
