Warp Platform API reference

Warp Platform API

API for creating, managing, and querying factory and cloud agent runs. Send work to factories, start standalone agents, list runs, and retrieve detailed run information.

Base URL: https://app.warp.dev/api/v1

Authentication: Bearer token (Warp API key). Obtain from account settings. Pass as Authorization: Bearer YOUR_API_KEY.

Full machine-readable spec: openapi.json

GET /networking/egress-ranges

List Warp-hosted agent egress ranges

Return the canonical IP network ranges used by outbound requests from Warp-hosted agents.

  • ()

GET /factory

List factories

List factories accessible to the authenticated principal, restricted to the request's active team when one is set. An optional team_uid query parameter overrides the active team and restricts results to a single team, and an optional search query parameter filters by a case-insensitive substring match on the factory name or alias.

  • ()
  • team_uid (query): Optional team UID to filter factories by ownership. Takes precedence over the X-Warp-Team-Uid header.
  • search (query): Case-insensitive substring search over the factory name and alias.
  • limit (query): Maximum number of factories to return (default 50, max 100).
  • cursor (query): Opaque cursor returned by a previous list response.

GET /factory/{uid}

Get a factory

Get a factory by its UID.

  • uid (path, required): The public UID of the factory.

GET /factory-inbox

List Factory inbox notifications

List unresolved notifications across factories authorized for the authenticated principal and active team. The default `mine` scope preserves the personal Inbox and requires user credentials. The `team` scope lists notifications assigned to any recipient and can be used by user or agent credentials. Personal read state (`is_read`) is included only in `mine` scope and omitted in `team` scope, including when filtering by recipient.

  • ()
  • scope (query): `mine` returns notifications assigned to the authenticated user and is the default. `team` returns notifications across live recipients in the authorized Factory and team scope.
  • factory_uid (query): Exact Factory UID filter, intersected with authorized factories.
  • recipient_uid (query): Exact public user UID filter within the authorized Factory and team scope. In `mine` scope this can only match the authenticated user.
  • limit (query): Maximum number of items to return. Defaults to 50.
  • cursor (query): Opaque cursor from page_info.next_cursor.

POST /factory-inbox/notifications/read

Mark inbox notifications as read

Mark a batch of notifications as read for the authenticated user after checking access to each factory. The caller must be a recipient of each existing notification, and the notification must remain active; otherwise its outcome is unsuccessful. Missing notifications are successful no-ops. Outcomes are returned in request order.

POST /factory-inbox/notifications/unread

Mark inbox notifications as unread

Mark a batch of notifications as unread for the authenticated user after checking access to each factory. The caller must be a recipient of each existing notification, and the notification must remain active; otherwise its outcome is unsuccessful. Missing notifications are successful no-ops. Outcomes are returned in request order.

POST /factory/{uid}/tasks

Create a factory task

Create a task in a factory, bound to an existing agent conversation. title and conversation_id are required. The stage defaults to TRIAGE. The conversation's most recent run must be owned by the factory's team, and a conversation may be bound to at most one live task across all factories.

  • uid (path, required): The public UID of the factory.

GET /factory/{uid}/tasks

List factory tasks

List the factory's tasks with optional filtering and search. List responses are lean by default; set full_list=true to include canonical ticket metadata and derived outputs for the returned page.

  • uid (path, required): The public UID of the factory.
  • stage (query): Filter by task stage. Can be specified multiple times to match any of the given stages.
  • created_by (query): Filter to tasks whose seed run was started by any of these teammates, each given as their email address. Can be specified multiple times to match any of the given teammates.
  • q (query): Case-insensitive substring search over the task title.
  • created_after (query): Filter to tasks created after this timestamp (RFC3339 format).
  • created_before (query): Filter to tasks created before this timestamp (RFC3339 format).
  • updated_after (query): Filter to tasks updated after this timestamp (RFC3339 format).
  • sort_by (query): Sort field for results.
  • sort_order (query): Sort direction.
  • limit (query): Maximum number of tasks to return (default 50, max 100).
  • cursor (query): Opaque cursor returned by a previous list response. Valid only for the sort_by/sort_order it was issued under; omit to restart the listing.
  • full_list (query): Include canonical ticket_source and ticket_id metadata from each task's bound run, plus its derived outputs. Defaults to false.
  • include_current_run (query): Include each task's current top-level run, resolved in one batch for the returned page. Defaults to false.

POST /factory/{uid}/runs

Dispatch a run to a factory

Dispatch a run to a factory, using prompt as the run's prompt and an optional title, ticket_ref, and ticket_url. Returns the created run; its factory task is created asynchronously and can be resolved afterwards with GET /factory/{uid}/task-by-run.

  • uid (path, required): The public UID of the factory.

GET /factory/{uid}/tasks/{task_uid}

Get a factory task

Get a task with its derived outputs, newest-first.

  • uid (path, required): The public UID of the factory.
  • task_uid (path, required): The public UID of the task.

PATCH /factory/{uid}/tasks/{task_uid}

Update a factory task

Partially update a task's title, description, and/or stage. Last write wins. Stage writes are unrestricted: any stage-to-stage transition is allowed, including moving backwards or to completion.

  • uid (path, required): The public UID of the factory.
  • task_uid (path, required): The public UID of the task.

DELETE /factory/{uid}/tasks/{task_uid}

Delete a factory task

Soft-delete a task. The task disappears from list and get responses immediately, and its conversation may be bound to a new task. Deleting a task never deletes artifacts or the conversation.

  • uid (path, required): The public UID of the factory.
  • task_uid (path, required): The public UID of the task.

POST /factory/{uid}/tasks/{task_uid}/cancel

Stop a factory task

Cancel the task's current top-level run and move the task to CANCELLED. Every non-terminal descendant of the root run is cancelled as well.

  • uid (path, required): The public UID of the factory.
  • task_uid (path, required): The public UID of the task.

GET /factory/{uid}/task-by-conversation

Get a factory task by conversation

Get the factory task bound to an agent conversation. Conversation bindings are unique across factories, but the lookup is factory-scoped: a task owned by a different factory is 404.

  • uid (path, required): The public UID of the factory.
  • conversation_id (query, required): The agent conversation ID the task is bound to.

GET /factory/{uid}/task-by-run

Get a factory task by run

Get the factory task that owns a run: the task bound to the conversation of the run's root ancestor. The lookup is factory-scoped: a task owned by a different factory is 404.

  • uid (path, required): The public UID of the factory.
  • run_id (query, required): Any run ID in the task's run tree.

GET /factory/{uid}/metrics

Get factory metrics

Aggregate productivity metrics for a factory over a UTC date range: run count, distinct PR count (from PR artifacts, deduped by URL at first appearance), autonomy, impact, and PR latency. Cost metrics live under /factory/{uid}/costs. Pass group_by_period to additionally receive per-period series aligned to period_list.

  • uid (path, required): The public UID of the factory.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • group_by_period (query): Optional binning granularity; when omitted, the response contains aggregates only. Binned requests are capped at 365 periods.

GET /factory/{uid}/costs/per-pr

Get factory cost per PR

Mean per-PR attributed cost for a factory over a UTC date range, with per-component dollar breakdowns. Previously served as cost_per_pr on GET /factory/{uid}/metrics. Pass group_by_period to additionally receive per-period series aligned to period_list.

  • uid (path, required): The public UID of the factory.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • group_by_period (query): Optional binning granularity; when omitted, the response contains aggregates only. Binned requests are capped at 365 periods.

GET /factory/{uid}/costs/breakdown

Get factory spend grouped by a dimension

The factory's spend over a UTC date range, grouped by source, user, agent, or model. groups lists every entity with nonzero spend in the range (uncapped); UNKNOWN sorts last. Pass group_by_period to additionally receive per-period series aligned to period_list.

  • uid (path, required): The public UID of the factory.
  • group_by (query, required): The dimension to group spend by.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • group_by_period (query): Optional binning granularity; when omitted, the response contains aggregates only. Binned requests are capped at 365 periods.

GET /factory/{uid}/costs/per-pr/top

Get the factory's most expensive PRs

The costliest PRs first seen in the range, most expensive first, with per-component cost breakdowns, attribution from each PR's earliest live root run, and PR detail collected from code-forge webhooks. PRs that predate webhook PR-fact collection still appear, with null detail fields.

  • uid (path, required): The public UID of the factory.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • limit (query): Maximum PRs to return. Defaults to 20; at most 50.

GET /factory/{uid}/pull-requests

List the factory's pull requests

One record per pull request produced by the factory's runs, newest opened first. A PR someone opened in one of the factory's repositories without a factory run (by hand, for example) is not listed. Each record carries the PR's identity, state and times, size, human interactions, the runs that produced it, and its cycle time. Pages are keyset-paginated: pass page_info.next_cursor back as cursor to continue. Pass updated_after to sync incrementally.

  • uid (path, required): The public UID of the factory.
  • limit (query): Records per page. Defaults to 50; at most 500.
  • cursor (query): Opaque cursor from a previous page's page_info.next_cursor.
  • repo (query): Only PRs in this repository, as owner/repo (case-insensitive).
  • state (query): Only PRs in these states. Can be specified multiple times to match any of the given states.
  • opened_after (query): Only PRs opened after this RFC3339 time (exclusive).
  • opened_before (query): Only PRs opened before this RFC3339 time (exclusive).
  • merged_after (query): Only PRs merged after this RFC3339 time (exclusive).
  • merged_before (query): Only PRs merged before this RFC3339 time (exclusive).
  • updated_after (query): Only PRs whose updated_at is after this RFC3339 time (exclusive). updated_at tracks the PR on the code host; fields derived from the factory's runs (runs, kickoff_at, human_interactions.follow_up_message, and the kickoff-based cycle_time stages) can change without moving it.

GET /factory/{uid}/metrics/run-breakdown

Get the factory's run counts grouped by a dimension

The factory's run counts over a UTC date range, grouped by one dimension. Pass group_by_period to additionally receive per-period series aligned to period_list.

  • uid (path, required): The public UID of the factory.
  • group_by (query, required): The dimension to group run counts by.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • group_by_period (query): Optional binning granularity; when omitted, the response contains aggregates only. Binned requests are capped at 365 periods.

GET /factory/{uid}/costs/per-pr/by-size

Get the factory's PR cost distribution grouped by PR size

The mean per-PR attributed cost of the factory's PRs first seen in a UTC date range, grouped by PR size. Pass group_by_period to additionally receive per-period mean series aligned to period_list.

  • uid (path, required): The public UID of the factory.
  • start_date (query): Inclusive RFC3339 range start (UTC). Defaults to end_date minus 30 days.
  • end_date (query): Exclusive RFC3339 range end (UTC). Defaults to now.
  • group_by_period (query): Optional binning granularity; when omitted, the response contains aggregates only. Binned requests are capped at 365 periods.

GET /agent

List available agent skills

Retrieve a list of available agents (skills) that can be used to run tasks. Agents are discovered from environments or a specific repository.

  • ()
  • repo (query): Optional repository specification to list agents from (format: "owner/repo"). If not provided, lists agents from all accessible environments.
  • refresh (query): When true, clears the agent list cache before fetching. Use this to force a refresh of the available agents.
  • sort_by (query): Sort order for the returned agents. - "name": Sort alphabetically by name (default) - "last_run": Sort by most recently used
  • include_malformed_skills (query): When true, includes skills whose SKILL.md file exists but is malformed. These variants will have a non-empty `error` field describing the parse failure. Defaults to false.

GET /agent/connected-self-hosted-workers

List connected self-hosted workers

Retrieve currently connected self-hosted workers for the authenticated principal's team. Worker presence is derived from worker websocket heartbeats and may be briefly stale.

  • ()

GET /agent/runs/{runId}/transcript

Get run transcript

Retrieve the raw conversation transcript for an agent run. Returns a 302 redirect to a time-limited download URL for the transcript.

  • runId (path, required): The unique identifier of the run

GET /agent/runs/{runId}/harness-usage

Get raw third-party harness usage

Return the latest cumulative raw usage snapshot retained for a Claude Code or Codex run. Missing metrics are represented as an unavailable result rather than zero. Access uses the same run view authorization as transcript reads.

  • runId (path, required)

POST /agent/run

Run an agent task

Spawn a cloud agent with a prompt and optional configuration. The agent will be queued for execution and assigned a unique run ID.

  • ()

POST /agent/runs

Run a cloud agent

Spawn a cloud agent with a prompt and optional configuration. The agent will be queued for execution and assigned a unique run ID.

  • ()

GET /agent/runs

List agent runs

Retrieve a paginated list of agent runs with optional filtering. Results default to `sort_by=updated_at` and `sort_order=desc`.

  • ()
  • limit (query): Maximum number of runs to return
  • cursor (query): Pagination cursor from previous response
  • sort_by (query): Sort field for results. - `updated_at`: Sort by last update timestamp (default) - `created_at`: Sort by creation timestamp - `title`: Sort alphabetically by run title - `agent`: Sort alphabetically by skill. Runs without a skill are grouped last.
  • sort_order (query): Sort direction
  • state (query): Filter by run state. Can be specified multiple times to match any of the given states.
  • task_status (query): Filter by high-level task status. Can be specified multiple times to match any value. `running` matches when the root or any descendant is queued, pending, claimed, or in progress. `failed`, `blocked`, `cancelled`, and `complete` match the root state only.
  • name (query): Filter by agent config name
  • model_id (query): Filter by model ID
  • creator (query): Filter by creator UID (user or service account)
  • executor (query): Filter by the user or agent that executed the run. This will often be the same as the creator, but not always: users may delegate tasks to agents.
  • source (query): Filter by run source type. Can be specified multiple times to match any of the given sources.
  • execution_location (query): Filter by where the run executed
  • created_after (query): Filter runs created after this timestamp (RFC3339 format)
  • created_before (query): Filter runs created before this timestamp (RFC3339 format)
  • updated_after (query): Filter runs updated after this timestamp (RFC3339 format)
  • environment_id (query): Filter runs by environment ID. Passing the literal value `empty-environment` matches runs with no environment configured, rather than omitting the parameter, which applies no environment filter at all. `empty-environment` can never collide with a real environment ID: every environment ID is exactly 22 characters drawn from `[A-Za-z0-9]`, while this sentinel contains a hyphen and is a different length.
  • skill (query): Filter runs by skill spec (e.g., "owner/repo:path/to/SKILL.md"). Alias for skill_spec.
  • skill_spec (query): Filter runs by skill spec (e.g., "owner/repo:path/to/SKILL.md")
  • schedule_id (query): Filter runs by the scheduled agent ID that created them
  • factory_uid (query): Filter runs by one or more factories. Repeating this parameter matches runs executed by an agent from any selected factory. A UID outside the caller's accessible factories matches nothing.
  • ancestor_run_id (query): Filter runs by ancestor run ID. The referenced run must exist and be accessible to the caller.
  • metadata (query): Filter by exact metadata key/value pairs using object notation (e.g. `metadata[ticket_id]=ACME-238`), combining multiple pairs with AND semantics, up to 5 per request. Returns `feature_not_available` when metadata filtering is not enabled.
  • artifact_type (query): Filter runs by artifact type
  • q (query): Search by full run ID or run URL, or fuzzy match across run title, prompt, and skill_spec

GET /agent/run-by-external-reference

Find the run that produced a given external reference URL

Reverse-looks up the agent run that created an external reference with the given URL. The URL is matched against the canonical locator stored when the artifact was reported. Returns 404 when no matching run exists or when the caller lacks access.

  • url (query, required): The canonical URL of the external reference artifact to look up.

GET /agent/runs/{runId}

Get run details

Retrieve detailed information about a specific agent run, including the full prompt, session link, and resolved configuration.

  • runId (path, required): The unique identifier of the run

GET /agent/runs/{runId}/timeline

Get run timeline

Retrieve chronological setup and lifecycle timeline events for an agent run.

  • runId (path, required): The unique identifier of the run

GET /agent/runs/{runId}/conversation

Get normalized run conversation

Retrieve a run's conversation as a normalized sequence of messages and nested steps. The response groups text, tool activity, and event content into structured blocks.

  • runId (path, required): The unique identifier of the run

POST /agent/runs/{runId}/cancel

Cancel a run

Cancel an agent run that is currently queued or in progress; once cancelled, the run transitions to a cancelled state. Not all runs can be cancelled: a run already in a terminal state, in PENDING, or of an unsupported type (e.g. local, GitHub Action) is rejected instead — see the error responses below for each case.

  • runId (path, required): The unique identifier of the run to cancel

POST /agent/runs/{runId}/followups

Submit a follow-up message for a run

Send a follow-up message to an existing run. The server transparently routes the message based on the current state of the run (still queued, actively running, or ended) and will resume the agent in a new sandbox if necessary. A 200 response means the follow-up was accepted; updated run state can be observed via `GET /agent/runs/{runId}`. A run that failed during environment setup keeps its retained session reachable for a bounded debug window. A follow-up sent to an eligible run in that window is delivered into the retained session to start or continue a debug agent, without reopening the run: it stays in its failed state, with its original failure message and error code unchanged.

  • runId (path, required): The unique identifier of the run

POST /agent/runs/{runId}/interrupt

Interrupt the turn currently running on a run

Cancel the request the agent is currently working on without ending the run or tearing down its sandbox. The run stays in progress and accepts follow-ups afterwards. Only live runs on the Warp harness can be interrupted; use `POST /agent/runs/{runId}/cancel` to end a run outright. A 202 means the platform accepted the cancel; the agent applies it asynchronously.

  • runId (path, required): The unique identifier of the run

GET /agent/runs/{runId}/handoff/attachments

List handoff snapshot attachments for a run

Return fresh presigned download URLs for handoff snapshot files uploaded by the latest ended execution of this run. An empty list is returned when no ended execution exists or no snapshot files were uploaded. This endpoint is useful for third-party harnesses that want to download the snapshot files produced by a previous execution before starting a handoff execution themselves.

  • runId (path, required): The unique identifier of the run

POST /agent/conversations/{conversation_id}/followups

Submit a follow-up message to the run behind a conversation

The same operation as `POST /agent/runs/{runId}/followups`, targeted by the conversation the run is serving rather than the run itself. `attachments` must name ids prepared through `POST /agent/conversations/{conversation_id}/attachments/prepare` (or the run-keyed prepare) for the run that is newest at that time. If a new run appears for the conversation between prepare and follow-up, the follow-up resolves to the new run and answers 422 `unknown_attachment`; prepare again. A handoff is a new execution of the same run and does not have this problem. `mode` only takes effect when the follow-up is queued ahead of the run starting or starts a new execution; a follow-up injected into a live session runs in the session's current mode.

  • conversation_id (path, required): The UUID of the Warp-native conversation

POST /agent/conversations/{conversation_id}/interrupt

Interrupt the turn running on the run behind a conversation

The same operation as `POST /agent/runs/{runId}/interrupt`, addressed by the conversation the run is serving. The run is picked with the same policy as the conversation follow-up route, and the caller must be able to view the conversation and the resolved run.

  • conversation_id (path, required): The UUID of the Warp-native conversation

GET /agent/conversations/{conversation_id}

Get normalized conversation

Retrieve a conversation directly by conversation ID in Warp's normalized task/message format.

  • conversation_id (path, required): The unique identifier of the conversation

GET /agent/conversations/{conversation_id}/transcript

Get conversation transcript

Retrieve the raw conversation transcript for a conversation. Returns a 302 redirect to a time-limited download URL for the transcript. Supported for third-party harness conversations (Claude Code, Codex, Gemini).

  • conversation_id (path, required): The unique identifier of the conversation

GET /agent/conversations/{conversation_id}/screenshots/{screenshot_uid}/download

Download a stored computer-use screenshot

Download a computer-use screenshot that was offloaded from the conversation's task history into object storage. The response is a redirect to a short-lived signed URL, so clients must follow redirects to receive the image. Requires view access to the conversation named in the path; a fork's history may reference screenshots stored under its source conversation's ID.

  • conversation_id (path, required): The unique identifier of the conversation that owns the screenshot
  • screenshot_uid (path, required): The unique identifier of the stored screenshot

POST /agent/schedules

Create a scheduled agent

Create a new scheduled agent that runs on a cron schedule. The agent will be triggered automatically based on the cron expression.

  • ()

GET /agent/schedules

List scheduled agents

Retrieve all scheduled agents accessible to the authenticated user. Results are sorted alphabetically by name.

  • ()

GET /agent/schedules/{scheduleId}

Get scheduled agent details

Retrieve detailed information about a specific scheduled agent, including its configuration, history, and next scheduled run time.

  • scheduleId (path, required): The unique identifier of the scheduled agent

PUT /agent/schedules/{scheduleId}

Update a scheduled agent

Update an existing scheduled agent's configuration. All fields except agent_config are required.

  • scheduleId (path, required): The unique identifier of the scheduled agent

DELETE /agent/schedules/{scheduleId}

Delete a scheduled agent

Delete a scheduled agent. This will stop all future scheduled runs.

  • scheduleId (path, required): The unique identifier of the scheduled agent

POST /agent/schedules/{scheduleId}/pause

Pause a scheduled agent

Pause a scheduled agent. The agent will not run until resumed.

  • scheduleId (path, required): The unique identifier of the scheduled agent

POST /agent/schedules/{scheduleId}/resume

Resume a scheduled agent

Resume a paused scheduled agent. The agent will start running according to its cron schedule.

  • scheduleId (path, required): The unique identifier of the scheduled agent

GET /agent/environments

List environments

Retrieve cloud environments accessible to the authenticated principal. Returns environments the caller owns, has been granted guest access to, or has accessed via link sharing.

  • ()
  • sort_by (query): Sort order for the returned environments. - `name`: alphabetical by environment name - `last_updated`: most recently updated first (default)

GET /agent/models

List available models

Retrieve the list of LLM models available to the authenticated user for agent runs. The response includes which model is the default, as well as per-model metadata such as provider, cost, and whether the model is currently disabled (and why).

GET /agent/artifacts/{artifactUid}

Get artifact details

Retrieve an artifact by its UUID: a time-limited signed download URL for downloadable file-like artifacts, or the current plan content inline for plan artifacts. Public artifacts can be read without authentication; private artifacts require the caller to be authenticated and authorized.

  • artifactUid (path, required): The unique identifier (UUID) of the artifact

GET /agent/artifacts/{artifactUid}/download

Download an artifact

Redirect to a temporary signed download URL for a downloadable artifact. Public artifacts can be downloaded without authentication; private artifacts require the caller to be authenticated and authorized.

  • artifactUid (path, required): The unique identifier (UUID) of the artifact

PATCH /factory/{uid}/scorers/{scorer_uid}

Update a scorer's definition

Apply a partial update to a scorer's definition; omitted fields are left unchanged, but at least one field must be provided, and the owning factory is immutable. Each update bumps the scorer's version without invalidating any scoring judge already in flight, since judges validate against the definition snapshot taken at dispatch time, and historical scores keep their recorded classification values. Supplying `scope_mode` or `agent_uids` replaces the scorer's scope in full.

  • scorer_uid (path, required): The scorer identifier

DELETE /factory/{uid}/scorers/{scorer_uid}

Delete a scorer

Permanently delete a scorer. This is not reversible and it is not an archive: the scorer's scoring attempts, scores, judge reasoning, self-improvement config, and self-improvement triage results go with it, and the scorer stops being readable through this API as soon as the call returns. The underlying rows and the judge-reasoning blobs stored outside the database are destroyed shortly afterwards by the deletion sweep, which removes each blob before the record that references it and retries until both are gone.

  • scorer_uid (path, required): The scorer identifier

POST /agent/identities

Create an agent

Create a new agent in the caller's active team. Agents act autonomously with their own permissions, configuration, and identity.

  • ()

GET /agent/identities

List agents

List all agents on the caller's team.

  • ()
  • factory_uid (query): Optional UID of a Factory to filter by. When provided, only agents linked to that factory are returned.

POST /factory/{uid}/scorers

Create a scorer

Create an active run scorer for a factory with either selected-agent or all-agent scope. Creating a scorer does not start scoring. Pass self_improvement_enabled to also turn on self-improvement for the new scorer in the same request; the scorer and its self-improvement config are created atomically.

GET /factory/{uid}/scorers

List agent scorers

List the scorers in the factory named in the path, including scope agents and aggregate scoring stats.

  • ()
  • start_date (query): Legacy summary range start (RFC3339 UTC, inclusive). Accepted and validated for compatibility; does not affect the list response. Must be provided together with end_date and be strictly before it.
  • end_date (query): Legacy summary range end (RFC3339 UTC, exclusive). See start_date.

GET /factory/{uid}/scorers/{scorer_uid}/results

List results for a scorer

List the scorer's most recent scoring attempts, newest first. A failed attempt carries no classification. Pagination is a keyset cursor over attempted_at with the attempt id as a stable tiebreak. Repeat `run_id` to return all matching results without pagination; unknown runs are omitted. Reasons are read from object storage only when include_reasons is true.

  • ()
  • scorer_uid (path, required): The scorer identifier
  • limit (query): Maximum number of results to return (1-100, default 50)
  • cursor (query): Opaque cursor returned by a previous list response.
  • include_reasons (query): Include reason availability and readable judge reasoning.
  • run_id (query): Exact run filters, repeated once per run. Values are trimmed and deduplicated; require 1-100 distinct nonblank runs when present. Cannot be combined with cursor or limit.

GET /factory/{uid}/scorers/{scorer_uid}/metrics

Get scorer metrics over a date range

Returns a period-aligned pass-rate series plus a full-range aggregate for the scorer, computed directly from every live score in [start_date, end_date). Binning follows the same day/week/month rules and 365-period cap as `GET /factory/{uid}/metrics`.

  • ()
  • scorer_uid (path, required): The scorer identifier
  • start_date (query): RFC3339 UTC range start, inclusive. Defaults to 30 days before end_date.
  • end_date (query): RFC3339 UTC range end, exclusive. Defaults to now.
  • group_by_period (query): Binning granularity for the series. Defaults to day.
  • include_cost (query): Include the scorer's judge-run cost for each period. Defaults to false.

POST /factory/{factory_uid}/runs/{run_id}/scorer_dispatch

Manually dispatch scorers for a run

Evaluate one run with the scorers in `scorer_uids`. To evaluate multiple runs with one scorer, use `/factory/{factory_uid}/scorers/{scorer_uid}/dispatch`. Manual dispatch skips automatic scoring's cool-down and sampling (including 0%) and supports older or previously scored runs. Requires manage access to the factory and view access to the run. The run must have a conversation and be executed by a factory agent, not be a scoring job. The run and scorers must belong to this factory and team. Each scorer must be configured for the run's agent and must not be benchmark-managed. Provide 1–100 scorer UUIDs. Run and scorer UUIDs must be nonzero. Invalid selections reject the whole request before any scoring jobs start. Returns dispatch outcomes, not completed scores. Valid requests can have individual failures; inspect each result's `status` and `error`.

  • factory_uid (path, required): The factory containing the run and scorers.
  • run_id (path, required)

POST /factory/{factory_uid}/scorers/{scorer_uid}/dispatch

Manually dispatch a scorer for selected runs

Evaluate the runs in `run_ids` with one scorer. To evaluate one run with multiple scorers, use `/factory/{factory_uid}/runs/{run_id}/scorer_dispatch`. Manual dispatch skips automatic scoring's cool-down and sampling (including 0%) and supports older or previously scored runs. Requires manage access to the factory and view access to every run. Runs must have conversations and be executed by factory agents, not be scoring jobs. The scorer and runs must belong to this factory and team. The scorer must be configured for each run's agent and must not be benchmark-managed. Provide 1–100 run UUIDs. Run and scorer UUIDs must be nonzero. Invalid selections reject the whole request before any scoring jobs start. Returns dispatch outcomes, not completed scores. Valid requests can have individual failures; inspect each result's `status` and `error`.

  • factory_uid (path, required): The factory containing the scorer and runs.
  • scorer_uid (path, required)

GET /factory/runs/{run_id}/scores

Read a run's current scores

List the current live attempt for each evaluation that has attempted the given run, most recent attempt first. Excludes a deleted evaluation's data. Requires only view access to the run, since reading scores is part of viewing the run.

  • run_id (path, required): The run identifier

GET /agent/identities/{uid}

Retrieve an agent

Retrieve a single agent by its unique identifier.

  • uid (path, required): The unique identifier of the agent

PUT /agent/identities/{uid}

Update an agent

Update an existing agent.

  • uid (path, required): The unique identifier of the agent

DELETE /agent/identities/{uid}

Delete an agent

Delete an agent. All API keys associated with the agent are deleted atomically.

  • uid (path, required): The unique identifier of the agent

GET /agent/sessions/{sessionUuid}/redirect

Get session redirect

Check whether a shared session should redirect to a conversation transcript, returning a conversation_id if the agent sandbox has finished and conversation data is available (or an empty object if no redirect is needed). Public and unauthenticated, so anonymous viewers can resolve a shared session link before signing in; access to the underlying transcript is still gated by conversation link-sharing.

  • sessionUuid (path, required): The UUID of the shared session

GET /agent/conversations/{conversationId}/redirect

Get conversation redirect

Check whether a conversation should redirect to a live shared session, returning a session_id if the underlying ambient agent task still has one (or an empty object if no redirect is needed). Public and unauthenticated, so anonymous viewers can resolve a shared conversation link before signing in; access to the underlying live session is still gated by the session-sharing service ACLs.

  • conversationId (path, required): The ID of the conversation

POST /factory/{factory_uid}/benchmarks

Create a benchmark suite

  • ()

GET /factory/{factory_uid}/benchmarks

List benchmark suites

  • ()
  • limit (query)
  • cursor (query)

GET /factory/{factory_uid}/benchmarks/{suite_uid}

Get a benchmark suite with its tasks and configurations

  • ()
  • ()

PATCH /factory/{factory_uid}/benchmarks/{suite_uid}

Edit a benchmark suite

  • ()
  • ()

DELETE /factory/{factory_uid}/benchmarks/{suite_uid}

Soft-delete a benchmark suite

  • ()
  • ()

POST /factory/{factory_uid}/benchmarks/{suite_uid}/tasks

Create a benchmark suite task

This adds a single hand-authored task to a suite, without needing to resend the whole task list. A title, prompt, and success criteria are required, and if a `source_run_id` is included, the caller must have permission to read that run. Adding the exact same task twice simply returns the existing one (so retrying is safe), while reusing a title with different content is rejected as a conflict — and on a `code.storage`-managed Factory, the task is saved as a file and returned from that file.

  • ()
  • ()

GET /factory/{factory_uid}/benchmarks/{suite_uid}/tasks/{task_uid}

Get one benchmark suite task

  • ()
  • ()
  • task_uid (path, required)

PATCH /factory/{factory_uid}/benchmarks/{suite_uid}/tasks/{task_uid}

Edit one benchmark suite task

Edits a single task in place without resending the suite's full task list. Omitted fields keep their current values. title, prompt, and success_criteria reject null and empty-after-trim values. An explicit null source_run_id clears provenance. An explicit empty starting_repo_refs or tags clears that field.

  • ()
  • ()
  • task_uid (path, required)

DELETE /factory/{factory_uid}/benchmarks/{suite_uid}/tasks/{task_uid}

Delete one benchmark suite task

  • ()
  • ()
  • task_uid (path, required)

POST /factory/{factory_uid}/benchmarks/{suite_uid}/runs

Launch a benchmark run from the current suite version

Each successful request creates a new run. Launch is not idempotent: disable automatic retries for this request and reconcile an uncertain outcome by listing runs before launching again. Retries are a client transport option, not a request-body field. In the TypeScript SDK, pass { maxRetries: 0 } as the request options. In the Python SDK, call create through client.with_options(max_retries=0). These options do not change execution retries within the benchmark run.

  • ()
  • ()

GET /factory/{factory_uid}/benchmarks/{suite_uid}/runs

List benchmark runs

List runs launched from this benchmark suite. Each entry contains the run's status and execution/scoring progress. Use `include` to add launch settings, aggregate results, or the creator's display name to each entry. The response contains a page of runs in `data` and continuation information in `page_info`. Retained runs remain readable after the suite is deleted; an unknown suite returns an empty list.

  • ()
  • ()
  • ()
  • state (query)
  • limit (query)
  • cursor (query)

GET /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}

Get benchmark run detail

Retrieve a benchmark run's status and execution/scoring progress. By default, the response omits launch settings and aggregate results. Use `include` to add these fields or the creator's display name. Retrieve trials separately for individual scores and execution history.

  • ()
  • ()
  • ()
  • ()

POST /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}/cancel

Cancel an in-flight benchmark run

  • ()
  • ()
  • ()

POST /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}/rescore

Rescore missing results for a completed benchmark run

  • ()
  • ()
  • ()

GET /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}/results

Get benchmark run results

Retrieve aggregate outcomes, coverage, and costs for the run. Task and tag filters select the trials used to calculate the results. By default, the response contains summary fields without detailed metric arrays; use `include` to add those arrays. Configuration and scorer filters limit returned metric rows without changing the summary or comparison populations. Results cover the whole selected dataset, independently of trial-list pages, and are not paginated.

  • ()
  • ()
  • ()
  • ()
  • ()
  • ()
  • ()
  • ()

GET /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}/trials

List benchmark trials or find the trial for an agent run

Each trial represents one task, configuration, and repetition within the benchmark run. The response contains a page of trials in `data` and continuation information in `page_info`. Use `include` to add scores, metrics, or retained execution history to each trial. Repeated values match any value within a filter; different filters must all match. To find the trial for a primary agent execution, pass `agent_run_id`. This returns zero or one trial, with `matched_attempt_number` identifying the matching attempt. Judge runs and spawned descendant runs do not match. This lookup accepts `include` and an omitted `limit` or `limit=1`, but no cursor or other filters. Filtering by scorer is not supported.

  • ()
  • ()
  • ()
  • ()
  • ()
  • ()
  • configuration_uid (query)
  • state (query)
  • agent_run_id (query)
  • limit (query)
  • cursor (query): Pass the previous response's page_info.next_cursor with the same filters to retrieve the next page.

GET /factory/{factory_uid}/benchmarks/{suite_uid}/runs/{run_uid}/trials/{trial_uid}

Retrieve an individual benchmark trial within a run

Retrieve the trial's execution and scoring status for one task, configuration, and repetition within the run. Include results to retrieve its scores and metrics, or details to retrieve retained execution attempts and judge history. Each requested expansion is complete. Selection and pagination parameters are not supported.

  • ()
  • ()
  • ()
  • ()
  • trial_uid (path, required)

GET /factory-files/schemas

List the supported Factory file schema versions

Returns every Factory file schema version this server can describe, with a link to each version's schema bundle.

  • If-None-Match (header): A previously returned ETag. A match returns 304 with no body.

GET /factory-files/schemas/{schema_version}

Get the JSON Schema bundle for one Factory file schema version

Returns every JSON Schema 2020-12 document describing one Factory file schema version, as a single bundle so the relative `$id` and `$ref` identities between the documents keep resolving.

  • schema_version (path, required): A Factory file schema version, for example `v1alpha1`.
  • If-None-Match (header): A previously returned ETag. A match returns 304 with no body.

GET /factory-files/schemas/{schema_version}/{document}

Get one Factory file schema document

Returns a single generated JSON Schema document on its own, rather than inside the bundle envelope, so it can be used directly as a schema reference. A document served here resolves its relative `$ref`s against its siblings at this same path, which is what each document's `$id` assumes, making the URL usable directly from an editor or YAML language server, for example: ```yaml # yaml-language-server: $schema=/api/v1/factory-files/schemas/v1alpha1/factory.schema.json ```

  • schema_version (path, required): Factory file schema version, such as v1alpha1
  • document (path, required): Document file name: common.schema.json, factory.schema.json, agent.schema.json, automation.schema.json, runner.schema.json, or scorer.schema.json