> ## Documentation Index
> Fetch the complete documentation index at: https://webscraping.titannet.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Runs and results

> How Titan MCP runs move from queued to complete, when a tool waits versus returns early, and how run_id ties an agent call back to the platform.

Every tool call that does work creates a **run**. A run is a Titan execution wearing an agent-friendly name, and the `run_id` you get back is literally the Titan `execution_id`.

That equivalence matters: anything you can do with an execution in the API, dashboard, analytics, or billing, you can do with a `run_id` from an agent.

## Synchronous or asynchronous

Tools try to return results inside the call. When work outlives the wait window, they hand back a `run_id` instead of failing.

| Tool                 | Default       | Why                                     |
| -------------------- | ------------- | --------------------------------------- |
| `titan_search`       | Waits         | Searches usually finish in seconds      |
| `titan_fetch`        | Waits         | Small batches finish quickly            |
| `titan_run_template` | Waits         | Most template runs are short            |
| `titan_crawl`        | Returns early | Crawls routinely exceed the wait window |

Override with `wait_for_completion`. Setting it to `false` returns a `run_id` immediately; setting it to `true` on a crawl only makes sense for small, shallow runs.

## The wait window

`timeout_seconds` controls how long a tool waits, capped at **30 seconds**.

Exceeding it is **not an error**. The run keeps going on Titan's side and you get:

```json theme={null}
{
  "run_id": "3c7d1a92-6f48-4b25-9e03-7d1a4c8b2f65",
  "status": "running",
  "warnings": [
    { "code": "next_step", "message": "call titan_get_run to retrieve pages" }
  ]
}
```

The `next_step` warning is the signal to poll. Re-issuing the original tool call instead would start a second billable run for work already in progress.

## Statuses

```mermaid theme={null}
stateDiagram-v2
    [*] --> queued
    queued --> running
    running --> completed
    running --> partial
    running --> failed
    running --> cancelled
    completed --> [*]
    partial --> [*]
    failed --> [*]
    cancelled --> [*]
```

| Status      | Terminal | Meaning                                              |
| ----------- | :------: | ---------------------------------------------------- |
| `queued`    |    No    | Accepted, waiting for a worker                       |
| `running`   |    No    | Work in progress                                     |
| `completed` |    Yes   | Finished; results delivered                          |
| `partial`   |    Yes   | Finished with some failures; usable results returned |
| `failed`    |    Yes   | Run failed without delivering results                |
| `cancelled` |    Yes   | Run was stopped                                      |

`partial` is common and usually fine. A fetch of 50 URLs where 47 succeed is a `partial` run with 47 usable pages.

## Reading results

Results arrive one of two ways:

**In the tool response** when the run finished inside the wait window. `titan_search` returns `results[]`, `titan_fetch` returns `pages[]` and `failed[]`, `titan_crawl` returns `discovered_urls[]` or `pages[]`.

**Through `titan_get_run`** when it did not. Records are aggregated across all steps of the run, paginated with `limit` and `offset`.

```json theme={null}
{ "run_id": "3c7d1a92-6f48-4b25-9e03-7d1a4c8b2f65", "limit": 100, "offset": 0 }
```

Compare `usage.records_returned` with `usage.records_available` to know whether more pages remain.

## The usage object

Every run reports what it cost:

| Field                  | Meaning                                    |
| ---------------------- | ------------------------------------------ |
| `backend_execution_id` | Same value as `run_id`                     |
| `billing_unit`         | Always `successful_delivery`               |
| `records_returned`     | Records in this response                   |
| `records_available`    | Total records the run produced             |
| `credits_estimated`    | Upper-bound estimate made before the run   |
| `credits_consumed`     | Credits actually charged                   |
| `billing_status`       | `pending`, `billable`, or `not_billable`   |
| `limit_hit`            | Crawl only: the run stopped at `max_pages` |
| `failure_count`        | Fetch only: URLs that produced no record   |

While a run is in flight, `billing_status` is `pending` and only `credits_estimated` is meaningful. Both settle once the run reaches a terminal status. See [Credits and usage](/docs/mcp/credits-and-usage).

## A run is a Titan execution

The same `run_id` works across the platform:

```bash theme={null}
# Full execution detail
curl -sS "$TITAN_API_URL/api/v1/executions/$RUN_ID" \
  -H "Authorization: Bearer $TITAN_TOKEN"

# Export everything the run produced
curl -sS "$TITAN_API_URL/api/v1/executions/$RUN_ID/results/export" \
  -H "Authorization: Bearer $TITAN_TOKEN"
```

That gives you a straightforward path from prototype to production: let an agent explore interactively, then rebuild the flow that worked against the [Task Service API](/docs/use-the-platform/use-the-task-service-api) with the same identifiers.

Agent runs also appear in your task list as [agentic tasks](/docs/about-platform/tasks#agentic-tasks), filterable by `mcp_capability` and `target_platform`.

## Handling runs well

| Situation               | Do this                                                                |
| ----------------------- | ---------------------------------------------------------------------- |
| Tool returned `running` | Poll `titan_get_run`; never re-issue the original call                 |
| Long crawl              | Leave `wait_for_completion` at its default and poll                    |
| Status is `partial`     | Use what came back; decide whether the failures are worth retrying     |
| Status is `failed`      | Check `warnings` and the error code before retrying                    |
| Many results            | Paginate with `limit` and `offset` rather than raising `limit` to 1000 |

## Next steps

* [titan\_get\_run](/docs/mcp/tools/titan-get-run) — polling and pagination in detail
* [Credits and usage](/docs/mcp/credits-and-usage) — what a run costs
* [Idempotency and retries](/docs/mcp/idempotency-and-retries) — retrying without paying twice
