---
title: "Run a task or a capability"
method: POST
path: "/api/v1/runs"
tags: ["Runs"]
---

# Run a task or a capability

`POST /api/v1/runs`

## Request

- Base URL: `https://unbrowse.ai`
- URL: `https://unbrowse.ai/api/v1/runs`
- Auth: one of:
  - OAuth 2 (authorization code, authorization URL `https://unbrowse.ai/authorize`, token URL `https://unbrowse.ai/oauth/token`, scopes: `unbrowse`)
  - HTTP bearer

Routes the task to the best capability (or runs the one named), fills its inputs and replays the site's API. Answers with the run: `succeeded` with a verified `result`, `input_required` with `requirements` to answer (POST /api/v1/runs/{runId}/responses), or `failed` with an `error`.

With `egress: "client"` the site requests are sent by you, from your own IP: the answer is `egress_required` with the next request(s) to send (method, URL, headers, body, and a ready `curl`). Send each one and post the raw response to /api/v1/egress/{egressId}; Unbrowse reads it and answers with the next request, or the finished run. Unbrowse decides every request and reads every response; it never contacts the site itself in such a run (no cloud browser, no proxy).

## Query parameters

- `deadlineMs` integer

## Headers

- `x-unbrowse-deadline-ms` integer

## Request body

- RunRequest
  - `task` string: What to do, in plain words. Unbrowse picks the capability.
  - `capability` string: A capability id to run instead of routing the task (from /api/v1/capabilities/search).
  - `targetUrl` string, uri: The site to do it on, when the task does not name one.
  - `input` object: The capability's inputs.
  - `accountRefs` string[]: Which kept logins to use.
  - `interactionMode` 'interactive' | 'unattended' | 'external_handler': unattended: a check nobody can clear fails instead of waiting.
  - `idempotencyKey` string, required: Repeat a request with the same key to get the same run.
  - `deadlineMs` integer: Answer within this many ms; past it 504 run_timeout with a runId to poll (the run keeps going). The x-unbrowse-deadline-ms header wins.
  - `egress` 'server' | 'client': client: you send the site requests from your own IP (see /api/v1/egress/{egressId}).
  - `select` string[]: Keep only these parts of the result. Dots walk keys, [] maps over a list, [n] takes one item, a final {a,b} keeps several keys. Applied to the answer after the run is verified; billing is the same. Paths that matched nothing come back in `selectMissing`; a malformed path is a 400 invalid_input naming it. Results over 40,000 characters are shortened (`truncated`), so select what you need.

## Response `200`

The run

- Run
  - `runId` string, required
  - `status` 'accepted' | 'working' | 'input_required' | 'succeeded' | 'failed' | 'outcome_unknown' | 'cancelled' | 'expired', required
  - `capabilityId` string, nullable
  - `phase` string
  - `stateRevision` integer
  - `result` unknown
  - `requirements` Object[]: What the run needs (status input_required).
  - `error` Object
  - `verified` boolean

## Other responses

- `202`: The run needs input (`input_required`), or, with egress client, the next site request to send (`egress_required`)
- `400`: An error
- `401`: Missing or invalid credentials. The WWW-Authenticate header names the protected-resource metadata.
- `402`: An error
- `404`: An error
- `429`: An error
- `504`: run_timeout: the run did not finish within its deadline. It keeps running: poll `GET /api/v1/runs/{runId}` with the runId given. A verified success is billed once when it lands; a failure is never billed. A retry with the same Idempotency-Key joins the same run.

---

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