# Work API

> The work Bash does on its computer: list it, read it, stop it or delete it.

Send `Authorization: Bearer vk_test_...` on every call.

## `GET /v1/tasks`

Its own page: [GET /v1/tasks](https://vestra.ai/developers/reference/api/work/get-v1-tasks.md)

All work across your users, or one user's with user_id. Filter by status, deployment, conversation or date too.

Your API key, scope `runtime` or `all`. On the card: [`ask`](https://vestra.ai/developers/ask.md). Over HTTP it is made from the contract: fill in every value.

### Request

Query:

- `limit` (`integer`): How many items per page, 1 to 100. Default 20.
- `cursor` (`string`): Where to go on from: the `next_cursor` of the page before, unchanged. Absent: the first page.
- `status` (`"queued" | "working" | "waiting" | "done" | "failed"`): Only tasks with this status.
- `user_id` (`string`): Only this user's, by your id for them.
- `deployment_id` (`string`): Only this deployment's (dep_...).
- `conversation_id` (`string`): Only this conversation's (conv_...).
- `created_after` (`string (date and time)`): Only tasks started after this ISO 8601 time.
- `created_before` (`string (date and time)`): Only tasks started before this ISO 8601 time.

### Answers 200

- `data` (`object[]`): The items on this page.
  - `id` (`string`): The task: one piece of work Bash started (task_...). Example: `task_91d`.
  - `object` (`"task"`): Always task.
  - `user_id` (`string | null`): Your id for its user; null on your company's own Bash.
  - `conversation_id` (`string | null`): The conversation that started it (conv_...); null when none did.
  - `deployment_id` (`string | null`): The deployment it runs on (dep_...); null when none.
  - `deployment_version` (`integer | null`): The version of that deployment it runs on; null when none.
  - `status` (`"queued" | "working" | "waiting" | "done" | "failed"`): queued: not started yet. working: running on the user's computer. waiting: it waits on an approval or a question. done or failed: it has ended.
  - `title` (`string | null`): What the work is, in a few words; null until Bash names it.
  - `progress` (`object[]`): Its plan, as its latest to-do list; empty when it has none.
    - `content` (`string`): One step of its plan.
    - `status` (`string`): Where that step is: pending, in_progress or completed.
  - `result` (`object`): What the work came to.
    - `text` (`string | null`): The work's answer: its final reply. Read one task for all of it; a list cuts it to 280 characters, as does a task that ended before its answer was recorded. Null until it has any, or when the work ended with no final reply.
    - `data` (`any | null`): Data it returned for an output_schema; null when it returned none.
  - `outcome` (`object | null`): Whether it met the success criteria of its message; null when there were none.
    - `met` (`boolean`): Whether it met the success criteria.
    - `reason` (`string`): Why, in a sentence.
  - `cost_usd` (`number`): What it has cost so far, in billed US dollars; the last charges can land a few seconds after it ends. Example: `0.0412`.
  - `cost_breakdown` (`object`): The same cost, by kind of spend.
    - `orchestrator` (`number`): Bash's own replies in the conversation, in billed US dollars; 0 on a piece of work.
    - `intelligence` (`number`): The thinking Bash did while it worked, in billed US dollars.
    - `tools` (`number`): The tools and apps Bash used, in billed US dollars.
    - `compute` (`number`): Time on Bash's computer, in billed US dollars.
    - `background` (`number`): Work Bash did in the background, such as remembering and tidying, in billed US dollars.
    - `voice` (`number`): Voice call time, in billed US dollars.
  - `created_at` (`string`): When it started, as an ISO 8601 time.
  - `updated_at` (`string`): When it last changed, as an ISO 8601 time.
- `next_cursor` (`string | null`): Send it as `cursor` for the next page; null on the last page.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/tasks" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/tasks/{task_id}`

Its own page: [GET /v1/tasks/{task_id}](https://vestra.ai/developers/reference/api/work/get-v1-tasks-task-id.md)

Status, title, the progress list, the result (text, and data when an output_schema was set), the outcome, cost so far.

Your API key, scope `runtime` or `all`. On the card: [`ask`](https://vestra.ai/developers/ask.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `task_id` (`string`, required): The piece of work's id (`task_...`).

### Answers 200

- `id` (`string`): The task: one piece of work Bash started (task_...). Example: `task_91d`.
- `object` (`"task"`): Always task.
- `user_id` (`string | null`): Your id for its user; null on your company's own Bash.
- `conversation_id` (`string | null`): The conversation that started it (conv_...); null when none did.
- `deployment_id` (`string | null`): The deployment it runs on (dep_...); null when none.
- `deployment_version` (`integer | null`): The version of that deployment it runs on; null when none.
- `status` (`"queued" | "working" | "waiting" | "done" | "failed"`): queued: not started yet. working: running on the user's computer. waiting: it waits on an approval or a question. done or failed: it has ended.
- `title` (`string | null`): What the work is, in a few words; null until Bash names it.
- `progress` (`object[]`): Its plan, as its latest to-do list; empty when it has none.
  - `content` (`string`): One step of its plan.
  - `status` (`string`): Where that step is: pending, in_progress or completed.
- `result` (`object`): What the work came to.
  - `text` (`string | null`): The work's answer: its final reply. Read one task for all of it; a list cuts it to 280 characters, as does a task that ended before its answer was recorded. Null until it has any, or when the work ended with no final reply.
  - `data` (`any | null`): Data it returned for an output_schema; null when it returned none.
- `outcome` (`object | null`): Whether it met the success criteria of its message; null when there were none.
  - `met` (`boolean`): Whether it met the success criteria.
  - `reason` (`string`): Why, in a sentence.
- `cost_usd` (`number`): What it has cost so far, in billed US dollars; the last charges can land a few seconds after it ends. Example: `0.0412`.
- `cost_breakdown` (`object`): The same cost, by kind of spend.
  - `orchestrator` (`number`): Bash's own replies in the conversation, in billed US dollars; 0 on a piece of work.
  - `intelligence` (`number`): The thinking Bash did while it worked, in billed US dollars.
  - `tools` (`number`): The tools and apps Bash used, in billed US dollars.
  - `compute` (`number`): Time on Bash's computer, in billed US dollars.
  - `background` (`number`): Work Bash did in the background, such as remembering and tidying, in billed US dollars.
  - `voice` (`number`): Voice call time, in billed US dollars.
- `created_at` (`string`): When it started, as an ISO 8601 time.
- `updated_at` (`string`): When it last changed, as an ISO 8601 time.

### Code

**HTTP**

```bash
curl "$VESTRA_BASE_URL/v1/tasks/{task_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `DELETE /v1/tasks/{task_id}`

Its own page: [DELETE /v1/tasks/{task_id}](https://vestra.ai/developers/reference/api/work/delete-v1-tasks-task-id.md)

Delete it and its outputs.

Your API key, scope `runtime` or `all`. On the card: [`ask`](https://vestra.ai/developers/ask.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `task_id` (`string`, required): The piece of work's id (`task_...`).

### Answers 200

- `id` (`string`): The task (task_...).
- `object` (`"task"`): Always task.
- `deleted` (`true`): Always true: it is gone, stopped first if it was running.

### Code

**HTTP**

```bash
curl -X DELETE "$VESTRA_BASE_URL/v1/tasks/{task_id}" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.

## `GET /v1/tasks/{task_id}/trace`

Its own page: [GET /v1/tasks/{task_id}/trace](https://vestra.ai/developers/reference/api/work/get-v1-tasks-task-id-trace.md)

Every step: tools called with a summary of inputs and outputs, timings, tokens and cost per turn.

Your API key, scope `runtime` or `all`. On the card: [`events`](https://vestra.ai/developers/events.md). Every call here is a checked sample.

### Request

Path:

- `task_id` (`string`, required): The piece of work's id (`task_...`).

### Answers 200

- `object` (`"task_trace"`): Always task_trace.
- `task_id` (`string`): The task (task_...).
- `steps` (`object[]`): Every tool Bash used, in order.
  - `tool_use_id` (`string`): The step: one use of a tool.
  - `name` (`string | null`): The tool Bash used; null when it was not recorded.
  - `input_summary` (`string | null`): What Bash did with it, in a line: never the raw input. Null when there is none.
  - `output_summary` (`string | null`): What came back, in a line; null when there is none.
  - `is_error` (`boolean`): Whether the step failed.
  - `started_at` (`string`): When it started, as an ISO 8601 time.
  - `finished_at` (`string | null`): When it finished, as an ISO 8601 time; null while running.
  - `duration_ms` (`number | null`): How long it took, in milliseconds; null while running.
- `turns` (`object[]`): Every call to the model, in order, with its tokens and cost.
  - `turn_id` (`string`): The model turn: one call to the model.
  - `model` (`string | null`): The model that answered; null when it was not recorded.
  - `input_tokens` (`number`): Tokens the model read.
  - `output_tokens` (`number`): Tokens the model wrote.
  - `cache_read_tokens` (`number`): Of the tokens it read, how many came from the cache, at a lower price.
  - `cost_usd` (`number`): What this turn cost, in billed US dollars.
  - `duration_ms` (`number | null`): How long it took, in milliseconds; null when not recorded.
  - `status` (`string | null`): How it ended, as recorded; null when not recorded.
  - `started_at` (`string`): When it started, as an ISO 8601 time.
- `totals` (`object`): The turns added up.
  - `input_tokens` (`number`): All tokens read.
  - `output_tokens` (`number`): All tokens written.
  - `cost_usd` (`number`): What every turn cost together, in billed US dollars.

### Code

**TypeScript**

```ts
const trace = await vestra.events.trace('task_91d');
```

**Python**

```python
trace = vestra.events.trace("task_91d")
```

**CLI**

```bash
vestra events task_91d
```

**HTTP**

```bash
# Stream a conversation live. If the connection drops, reconnect with the last seq you saw.
curl -N "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Last-Event-ID: 41"

# Read the same events as JSON. You get them in pages, after the seq you give.
curl "$VESTRA_BASE_URL/v1/conversations/conv_8f2k/events?format=json&after=41" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Read a task afterwards. You get every step of one task, with tokens and cost per turn.
curl "$VESTRA_BASE_URL/v1/tasks/task_91d/trace" \
  -H "Authorization: Bearer $VESTRA_API_KEY"

# Send events to your server. Register a URL and the events it wants. The signing secret is shown only once.
curl "$VESTRA_BASE_URL/v1/webhooks" \
  -H "Authorization: Bearer $VESTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://hooks.example.com/vestra", "events": ["task.completed", "interaction.created", "usage.cap_reached"] }'

# Catch up on what you missed. List the events your webhooks were sent, newest first.
curl "$VESTRA_BASE_URL/v1/events?type=task.failed" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**MCP**

```json
{
  "method": "tools/call",
  "params": {
    "name": "events",
    "arguments": { "user": "traveller-42", "conversation": "conv_8f2k", "after": 0 }
  }
}
```

## `POST /v1/tasks/{task_id}/stop`

Its own page: [POST /v1/tasks/{task_id}/stop](https://vestra.ai/developers/reference/api/work/post-v1-tasks-task-id-stop.md)

Stop this piece of work only.

Your API key, scope `runtime` or `all`. On the card: [`ask`](https://vestra.ai/developers/ask.md). Over HTTP it is made from the contract: fill in each {…} and every value.

### Request

Path:

- `task_id` (`string`, required): The piece of work's id (`task_...`).

Headers:

- `Idempotency-Key` (`string`): Send the same key to retry this call safely for 24 hours.

### Answers 200

- `task` (`object`): The task, after the stop.
  - `id` (`string`): The task: one piece of work Bash started (task_...). Example: `task_91d`.
  - `object` (`"task"`): Always task.
  - `user_id` (`string | null`): Your id for its user; null on your company's own Bash.
  - `conversation_id` (`string | null`): The conversation that started it (conv_...); null when none did.
  - `deployment_id` (`string | null`): The deployment it runs on (dep_...); null when none.
  - `deployment_version` (`integer | null`): The version of that deployment it runs on; null when none.
  - `status` (`"queued" | "working" | "waiting" | "done" | "failed"`): queued: not started yet. working: running on the user's computer. waiting: it waits on an approval or a question. done or failed: it has ended.
  - `title` (`string | null`): What the work is, in a few words; null until Bash names it.
  - `progress` (`object[]`): Its plan, as its latest to-do list; empty when it has none.
    - `content` (`string`): One step of its plan.
    - `status` (`string`): Where that step is: pending, in_progress or completed.
  - `result` (`object`): What the work came to.
    - `text` (`string | null`): The work's answer: its final reply. Read one task for all of it; a list cuts it to 280 characters, as does a task that ended before its answer was recorded. Null until it has any, or when the work ended with no final reply.
    - `data` (`any | null`): Data it returned for an output_schema; null when it returned none.
  - `outcome` (`object | null`): Whether it met the success criteria of its message; null when there were none.
    - `met` (`boolean`): Whether it met the success criteria.
    - `reason` (`string`): Why, in a sentence.
  - `cost_usd` (`number`): What it has cost so far, in billed US dollars; the last charges can land a few seconds after it ends. Example: `0.0412`.
  - `cost_breakdown` (`object`): The same cost, by kind of spend.
    - `orchestrator` (`number`): Bash's own replies in the conversation, in billed US dollars; 0 on a piece of work.
    - `intelligence` (`number`): The thinking Bash did while it worked, in billed US dollars.
    - `tools` (`number`): The tools and apps Bash used, in billed US dollars.
    - `compute` (`number`): Time on Bash's computer, in billed US dollars.
    - `background` (`number`): Work Bash did in the background, such as remembering and tidying, in billed US dollars.
    - `voice` (`number`): Voice call time, in billed US dollars.
  - `created_at` (`string`): When it started, as an ISO 8601 time.
  - `updated_at` (`string`): When it last changed, as an ISO 8601 time.
- `delivered` (`boolean`): Whether the stop surely reached the work.
- `reason` (`"local_relay_down" | "nothing_to_kill" | "kill_not_permitted" | "not_running" | null`): Why the stop did not land; null when it did. not_running: it was at rest, so nothing was sent. nothing_to_kill: nothing was running. local_relay_down: it runs on the user's own computer, which cannot be reached. kill_not_permitted: it could not be reached, so it may still be running.

### Code

**HTTP**

```bash
curl -X POST "$VESTRA_BASE_URL/v1/tasks/{task_id}/stop" \
  -H "Authorization: Bearer $VESTRA_API_KEY"
```

**TypeScript, Python, CLI, MCP**: No sample in your language for this route, so here it is over HTTP.
