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

# Get Execution

Use this API to fetch an execution document by ID. This is the polling endpoint: poll until `execution.status !== "running"`. Set `includeResults: true` to also fetch the per-URL findings subcollection.

# Endpoint

`POST https://api.velt.dev/v2/agents/execution/get`

# Headers

**x-velt-api-key** `string` *required*

Your API key.

**x-velt-auth-token** `string` *required*

Your [Auth Token](https://velt.dev/docs/security/auth-tokens.md).

# Body

#### Params

**data** `object` *required*

**properties**

**executionId** `string` *required*

Min 1 char. Execution ID returned from [Run Execution](https://velt.dev/docs/api-reference/rest-apis/v2/agents/execution/run.md).

**includeResults** `boolean`

Include the full per-URL results subcollection. Default: `false`.

## **Example Requests**

#### 1. Poll status only

```JSON theme={null}
{
  "data": {
    "executionId": "exec_1711900000000_abc123def456"
  }
}
```

#### 2. Fetch with full results

```JSON theme={null}
{
  "data": {
    "executionId": "exec_1711900000000_abc123def456",
    "includeResults": true
  }
}
```

# Response

#### Success Response (execution document)

```JSON theme={null}
{
  "result": {
    "status": "success",
    "message": "Execution fetched successfully",
    "data": {
      "execution": {
        "id": "exec_1711900000000_abc123def456",
        "agentId": "abc123def456",
        "agentName": "Brand Consistency Checker",
        "agentVersion": 3,
        "metadata": {
          "organizationId": "org_001",
          "documentId": "doc_001"
        },
        "config": {
          "seedUrl": "https://example.com",
          "crossPageExecute": true,
          "maxUrlsToProcess": 25,
          "deviceType": "desktop",
          "crawlerConfig": { "maxPages": 100, "timeout": 300000, "maxDepth": 0 }
        },
        "status": "passed",
        "startedAt": 1711900000000,
        "completedAt": 1711900150000,
        "durationMs": 150000,
        "trigger": "standalone",
        "workflowExecutionId": null,
        "previousExecutionId": null,
        "ranBy": { "userId": "user_123", "name": "Jane Doe", "email": "jane@example.com" },
        "resultsSummary": {
          "totalFindings": 7,
          "totalAnnotationsCreated": 7,
          "urlsProcessed": 12,
          "urlsWithFindings": 5,
          "issuesCreated": 7,
          "summary": "Found 7 issues across 12 pages. 7 annotations created."
        },
        "crawlerResults": { "status": "completed", "totalUrlsFound": 12, "duration": 45000, "pagesVisited": 12 },
        "llmModel": "claude/claude-opus-5-5",
        "llmModels": ["claude/claude-opus-5-5"],
        "tokenUsage": { "promptTokens": 12500, "completionTokens": 3200, "thoughtsTokens": 0, "totalTokens": 15700 }
      }
    }
  }
}
```

**Execution document field reference:**

| Field | Type | Description |
| - | - | - |
| `id` | string | Execution ID (Firestore doc ID). |
| `agentId` | string | Agent that was executed. |
| `agentName` | string | Denormalized agent display name. Built-in display names can change between releases, so identify an agent by `agentId`. |
| `agentVersion` | number | Agent config version at execution time (pinned). |
| `metadata.organizationId` | string | The `organizationId` you passed on Run Execution. Empty string when absent. |
| `metadata.documentId` | string | The `documentId` you passed on Run Execution. Empty string when absent. |
| `config.seedUrl` | string | The seed URL provided by the user. For a run started with `urls`, the first page in the list. |
| `config.crossPageExecute` | boolean | Whether cross-page mode was used. For a run started with `urls`, `true` when the list had more than one page. |
| `config.maxUrlsToProcess` | number | Max URLs limit. For a run started with `urls`, the number of pages in the list. |
| `config.pageSource` | string \| undefined | `"list"` when the run was started with `urls` on [Run Execution](https://velt.dev/docs/api-reference/rest-apis/v2/agents/execution/run.md), so the pages were supplied rather than discovered. Absent otherwise. |
| `config.deviceType` | string | Device mode emulated for this execution: `"mobile"` or `"desktop"`. Default: `"desktop"`. |
| `config.crawlerConfig` | object \| undefined | Crawler config (only when `crossPageExecute: true`). |
| `status` | string | `"running"`, `"passed"`, `"failed"`, `"partial"`, `"error"`, or `"skipped"`. See [statuses](https://velt.dev/docs/ai/agents/overview.md#execution-statuses). |
| `startedAt` | number | Epoch ms when execution started. |
| `completedAt` | number \| null | Epoch ms when completed. Null while running. |
| `durationMs` | number \| null | Total duration in ms. Null while running. |
| `error` | object \| undefined | Populated when any URL/batch failed: on `"error"` or `"partial"` (and may co-exist with `"failed"`). |
| `error.code` | string | Error code (`TIMEOUT`, `LLM_ERROR`, `LLM_RATE_LIMITED`, `MALFORMED_RESPONSE`, `CRAWLER_ERROR`, `CONTEXT_GATHERING_ERROR`, `POST_PROCESS_ERROR`, `INTERNAL`, or one of the [run-level codes](#run-level-error-codes) below). |
| `error.message` | string | Human-readable error description. |
| `error.advisoryComment` | string \| undefined | Advisory comment text posted to the document. |
| `error.retryable` | boolean | Whether this error can be retried. |
| `error.occurredAt` | number | Epoch ms when the error occurred. |
| `error.providerFailures` | object\[] \| undefined | Only with `error.code` `LLM_ERROR`, when every model provider failed: one entry per provider, in fallback order, at most 5. See [Provider failures](#provider-failures). |
| `trigger` | string | `"standalone"` or `"workflow"`. |
| `workflowExecutionId` | string \| null | Parent workflow execution ID (if workflow-triggered). |
| `previousExecutionId` | string \| null | Previous execution ID (set on reruns). |
| `ranBy` | object | `{ userId, name, email }` of who triggered. |
| `resultsSummary.totalFindings` | number | Total findings (after guardrails filtering). |
| `resultsSummary.totalAnnotationsCreated` | number | Annotations created. Re-runs first clear the prior run's suggestions per URL (delete-and-recreate), so this counts the fresh annotations written by this run. |
| `resultsSummary.urlsProcessed` | number | URLs that were processed. |
| `resultsSummary.urlsWithFindings` | number | URLs that had at least one finding. |
| `resultsSummary.urlsErrored` | number \| undefined | URLs whose agent run failed. `0 < urlsErrored < urlsProcessed` → `partial`; `urlsErrored >= urlsProcessed` (≥1 processed) → `error`. |
| `resultsSummary.erroredUrls` | array \| undefined | The failing pages, `{ url, message, providerFailures? }`, at most 50, also while the run is still running: the first 50 failing pages are kept. `providerFailures` is set when the page failed because every model provider failed (see [Provider failures](#provider-failures)). |
| `resultsSummary.urlsSiteAccessBlocked` | number \| undefined | Of `urlsErrored`, pages the run could not open because the site is behind a password or sign-in: no credential is stored for the site (`error.code` `SITE_ACCESS_REQUIRED`), or the site rejected the stored one (`SITE_ACCESS_FAILED`). Absent when no page was blocked. |
| `resultsSummary.urlsReused` | number \| undefined | Of `urlsProcessed`, pages where change detection kept the agent's previous findings because the page had not changed. The agent did not run on them. Absent when none. |
| `resultsSummary.findingsReused` | number \| undefined | Of `totalFindings`, findings copied from an earlier run onto the `urlsReused` pages. Their comments from that run stand, so `totalAnnotationsCreated` does not count them. Absent when none. |
| `resultsSummary.issuesCreated` | number | Equals `totalFindings`, reused findings included (backwards compat). |
| `resultsSummary.severityCounts` | object \| undefined | Finding counts keyed by severity, e.g. `{ "high": 2, "medium": 5, "low": 1 }`. Sparse: only severities with at least one finding are present, so treat a missing key as `0`. Possible keys are `critical`, `high`, `medium`, `low`, `info`. Absent entirely when the run produced no findings. |
| `resultsSummary.findings` | object\[] \| undefined | Sample of the run's findings for at-a-glance display, each `{ title, description, severity, sourceUrl?, issueType?, url?, evidence? }`. At most 50, the top ones by severity, also while the run is still running. Absent when the run produced no findings. Use `includeResults: true` for the complete per-URL findings. `evidence` is the compact form of the finding's [evidence](#finding-evidence). When the agent wrote no description, `description` is filled from the evidence text as `Found in: "<text around it>"` or `Found: "<text>"`, followed by the viewport in parentheses when it is known, for example `Found: "Lorem ipsum dolor" (phone).` It never quotes a CSS selector, and stays empty when the evidence has no text. |
| `resultsSummary.summary` | string \| null | Human-readable summary. Null while running. |
| `resultsSummary.matchResult` | object \| undefined | **Legacy.** Match-and-merge outcome (`{ created, skipped, resolved }`) written by the retired match-and-merge dedup. Present only on old execution documents; new executions use per-URL delete-and-recreate and never write this field. |
| `crawlerResults` | object \| undefined | Only populated when `crossPageExecute: true`. For a run started with `urls`, `status` is `"skipped"` or `"completed"` with `urlsCount` equal to the number of pages in the list: nothing was crawled. |
| `llmModel` | string \| undefined | LLM model that answered, as `provider/model` (e.g. `"claude/claude-opus-5-5"`, `"gemini/gemini-3.6-flash"`). On a run over several pages, the model of the last page processed. |
| `llmModels` | string\[] \| undefined | Every model that answered across the whole run, in the order first seen, for example `["claude/claude-opus-5-5", "claude/claude-sonnet-5-5"]` for a browser agent and the model of its browser steps, or two models when a call fell back. Absent when no model was called. |
| `providerFallbacks` | object\[] \| undefined | Present only when a model call fell back and still succeeded: the requested provider failed and a later one answered, so `llmModel` names the later one. Same entries as `error.providerFailures`. The same failure (provider, model, status, and code) is listed once per run, at most 10 entries, also while the run is still running. See [Provider failures](#provider-failures). |
| `warnings` | object\[] \| undefined | Non-blocking warnings stamped when the run started, such as `{ "code": "pages-truncated", "pagesTotal": 1200, "pagesRun": 500 }` when the `pageListTotal` sent to [Run Execution](https://velt.dev/docs/api-reference/rest-apis/v2/agents/execution/run.md) was larger than the pages the run reviews. |
| `tokenUsage` | object | `{ promptTokens, completionTokens, thoughtsTokens, totalTokens }`. |

> [!NOTE]
>
> Change detection only measures today: every agent still runs on every page, so `urlsReused` and `findingsReused` are absent until it is switched on. See the run-control keys of [Run Execution](https://velt.dev/docs/api-reference/rest-apis/v2/agents/execution/run.md).

> [!NOTE]
>
> The legacy execution-document fields `knowledgeRetrieved` / `knowledgeCached` / `degraded` have been **removed**. Memory-RAG runtime signals now live only on the in-memory execution result and are consumed internally by the guardrails processor; they are not persisted on the execution document.

#### Run-level error codes

These codes end the whole execution with status `error` and `error.retryable: true`, except on a run over several pages, as described below the table. To review the page, start a new run.

| `error.code` | Meaning |
| - | - |
| `TASK_DISPATCH_FAILED` | The run could not be started after its execution was created, so nothing was reviewed. [Run Execution](https://velt.dev/docs/api-reference/rest-apis/v2/agents/execution/run.md) returned `INTERNAL` for it. |
| `STALE_RUN` | The run stopped making progress. A new run of the same agent on the same document ended it and started in its place. |
| `SUITE_TIMEOUT` | The agent ran with others through `agentIds` and did not finish within the time limit those agents share (25 minutes per delivery). |
| `RUN_ATTEMPTS_EXHAUSTED` | The run could not finish after several attempts, for example because its instance kept crashing, so it was not tried again. |
| `MALFORMED_TASK` | The run could not start because its task was incomplete. |

On a run over several pages, these two codes can also end a single page instead of the run. A page that runs out of time in an `agentIds` run (`SUITE_TIMEOUT`), or whose deliveries keep failing for 3 deliveries (`RUN_ATTEMPTS_EXHAUSTED`), is counted as an errored page of each execution it belongs to: `resultsSummary.urlsErrored` counts it, `resultsSummary.erroredUrls` lists it with `The run took too long and was stopped.` or `The run could not finish after several tries.`, and `error.code` carries the code. The other pages still count, so the execution ends `partial` when some pages succeed. A crawl that found a single page is the exception: that page is the whole run, and `SUITE_TIMEOUT` ends it.

A run whose crawl fails (`crossPageExecute: true`) ends with status `error` and `error.code` `CRAWLER_ERROR`.

#### Provider failures

Entries of `error.providerFailures`, `resultsSummary.erroredUrls[].providerFailures`, and `providerFallbacks` describe why one model provider failed. They never contain the request: no prompt, page text, or body.

| Field | Type | Description |
| - | - | - |
| `provider` | string | `"claude"`, `"openai"`, or `"gemini"`. |
| `model` | string \| undefined | The model the call asked for. |
| `status` | number \| undefined | HTTP status the provider answered with. Absent for a network failure. |
| `code` | string \| undefined | The provider's error type or code, such as `overloaded_error` or `rate_limit_exceeded`. `"refusal"` when Claude declined the request on a safety classifier, and the call moved to the next provider. |
| `message` | string | The provider's message, at most 200 characters, with keys, tokens, provider account IDs, and request IDs replaced by `[redacted]`. A message about billing, credits, or quota reads `The provider refused the request for an account reason (billing, credits or quota).`, one about a rate limit reads `The provider rate limited the request.`, and a refusal reads `The model declined the request. (<category>)`. `status` and `code` still say what happened. |

```JSON theme={null}
"providerFallbacks": [
  {
    "provider": "claude",
    "model": "claude-opus-5-5",
    "status": 529,
    "code": "overloaded_error",
    "message": "Overloaded"
  }
]
```

#### Success Response (with results, `includeResults: true`)

When `includeResults` is true, a `results` array is included alongside `execution`:

```JSON theme={null}
{
  "result": {
    "status": "success",
    "message": "Execution fetched successfully",
    "data": {
      "execution": "...same as above...",
      "results": [
        {
          "id": "a1b2c3d4e5f6",
          "url": "https://example.com",
          "urlHash": "a1b2c3d4e5f6",
          "agentId": "abc123def456",
          "agentName": "Brand Guidelines Checker",
          "agentResult": {
            "status": "completed",
            "summary": "Found 1 typography issue on the hero section.",
            "issueCount": 1,
            "findingsCount": 1,
            "findings": [
              {
                "id": "finding-1",
                "title": "Heading uses wrong font",
                "description": "The h1 element uses 'Arial' instead of the brand font 'Inter'",
                "severity": "high",
                "targetText": "Welcome to Example",
                "occurrence": 1,
                "sourceUrl": "https://example.com",
                "suggestion": "Change font-family to 'Inter' for the h1 element",
                "htmlSelector": "h1.hero-title",
                "targetElementXpath": "/html/body/main/section[1]/h1",
                "isPageLevel": false,
                "issueType": "brand-font",
                "confidence": 92
              }
            ]
          },
          "findingCount": 1,
          "processedAt": 1711900050000
        }
      ]
    }
  }
}
```

**Per-URL result fields:**

| Field | Type | Description |
| - | - | - |
| `id` | string | Result document ID. Same value as `urlHash`. |
| `url` | string | The URL that was analyzed. |
| `urlHash` | string | MD5 hash of the URL. |
| `agentId` | string | ID of the agent that produced this result. |
| `agentName` | string | Name of the agent at the time of the run. |
| `agentResult` | object | The agent's output for this URL. Findings live here, not at the top level. See below. |
| `findingCount` | number | Number of findings for this URL. Mirrors `agentResult.issueCount`. |
| `processedAt` | number | Epoch ms when this URL was processed. |

> [!NOTE]
>
> Findings are nested under `agentResult.findings`, not on the result row itself. Read `results[i].agentResult.findings`. Annotation counts are not reported per URL; use `resultsSummary.totalAnnotationsCreated` for the run-level total.

**Agent result fields (`agentResult`):**

| Field | Type | Description |
| - | - | - |
| `status` | string | `"completed"` or `"failed"` for this URL. |
| `agentId` | string | Duplicate of the row-level `agentId`. |
| `agentName` | string | Duplicate of the row-level `agentName`. |
| `summary` | string \| undefined | Run-level analysis summary, copied onto each URL row. Present only when the agent returned a flat findings list rather than a per-URL breakdown, so it is the same string for every URL in the run. |
| `issueCount` | number | Number of issues the agent raised for this URL. |
| `findingsCount` | number | Number of findings the agent raised for this URL. Equal to the length of `findings` unless `findingsTruncated` is set. |
| `findings` | object\[] | Array of `AgentFinding` objects (see below). |
| `evidenceDropped` | boolean \| undefined | `true` when the page's findings were too large for its result document (800 KiB of findings), so they are stored without `evidence`. |
| `findingsTruncated` | number \| undefined | Set when the findings did not fit even without `evidence`: how many were left out. The first findings that fit are stored, and `issueCount` and `findingsCount` still count every finding. |
| `report` | object \| undefined | The agent's own per-page report, for agents whose output is more than findings, such as `migration-parity` and `content-request-list`. See [Migration Parity](https://velt.dev/docs/ai/agents/overview.md#migration-parity) and [Content Request List](https://velt.dev/docs/ai/agents/overview.md#content-request-list). |
| `error` | string \| null | Failure message for this URL. `null` when the URL completed successfully. Always present, so test for failure with `status === "failed"`, not with the presence of this field. |

**Finding fields (`AgentFinding`):**

| Field | Type | Description |
| - | - | - |
| `id` | string | Unique finding ID (e.g. `"finding-1"`). |
| `title` | string | Short title/summary. |
| `description` | string | Detailed description. |
| `severity` | string | `"critical"`, `"high"`, `"medium"`, `"low"`, `"info"`. |
| `targetText` | string | Exact DOM text. Empty string for image/non-text findings. |
| `occurrence` | number | 1-based occurrence index of `targetText` on the page. |
| `sourceUrl` | string | URL where the finding was detected. |
| `suggestion` | string | Suggested fix. |
| `suggestedFix` | string | The exact replacement text, when the agent knows it (for example a corrected spelling). Absent otherwise. A Proofreader spelling finding with several possible corrections and none picked has no `suggestedFix`, and its `suggestion` is `Check the spelling.` |
| `htmlSelector` | string | CSS selector of the DOM element. |
| `targetElementXpath` | string | XPath of the DOM element. |
| `isPageLevel` | boolean | `true` for visual/layout findings; `false` when `targetText` matches DOM text. |
| `issueType` | string | Issue classification tag (e.g. `"casing"`, `"pii"`, `"spelling"`, `"broken-link"`). Built-in values are listed in [Issue types](https://velt.dev/docs/ai/agents/overview.md#issue-types). |
| `confidence` | number | 0–100 confidence score reported by the agent. |
| `commentId` | string | Comment annotation ID (populated after annotation creation). |
| `source` | string | `"instructions"` or `"knowledge"`. |
| `reasonExtras` | object | Agent-specific details, also copied onto the comment annotation's `agent.reason`. Includes `sourceAnnotationId` and `sourcePageUrl` when the run set them in `userContext`. |
| `metadata` | object | Agent-specific details kept on the finding, such as `labels` and `differences` on the Consistency Checker's visual findings. |
| `evidence` | object | What the finding rests on. See [Finding evidence](#finding-evidence). Absent when the agent captured nothing. |

#### Finding evidence

`evidence` shows what a finding rests on, so it can be judged without opening the page. Every key is optional and absent when unknown. The compact form in `resultsSummary.findings` uses the smaller limits in parentheses.

| Field | Type | Description |
| - | - | - |
| `selector` | string | CSS selector of the element. Left out, never cut, when it is too long. |
| `text` | string | The exact offending text, at most 200 characters (160). |
| `context` | string | The text around it, at most 300 characters (160). |
| `html` | string | The element's markup, at most 500 characters (240), with attributes trimmed to a short allowlist, script and style bodies removed, and URLs stripped of their query and fragment. Render it as text: it is a picture of the markup, never markup to insert into a page. |
| `ancestors` | string\[] | Up to 6 (4) ancestor tokens, nearest first, such as `section.hero[role=region]`. |
| `viewport` | string | Where the facts were captured: `"desktop"`, `"tablet"`, or `"phone"`. |
| `rect` | object | `{ x, y, width, height }`: the element's box at capture, in CSS pixels. |
| `visible` | boolean | Whether the element was rendered at capture. |

The whole object stays under about 2 KB (1 KB). Token-like strings in `text`, `context`, and `html` are redacted, and evidence never carries cookies, typed form values, or full page HTML.

#### Failure Response

```JSON theme={null}
{
  "error": {
    "message": "ERROR_MESSAGE",
    "status": "NOT_FOUND"
  }
}
```

**Errors:** `NOT_FOUND` (`Execution not found: {executionId}` or `Store database not found`).

```js theme={null}
{
  "result": {
    "status": "success",
    "message": "Execution fetched successfully",
    "data": {
      "execution": {
        "id": "exec_1711900000000_abc123def456",
        "status": "running",
        "startedAt": 1711900000000,
        "completedAt": null,
        "durationMs": null
      }
    }
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.