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

# Get Run

> Returns one run with its lifecycle status and aggregate progress, ensuring it belongs to the API key's company. A run batches conversations rather than replacing them: it mints one conversation per contact, and `progress` counts those. For the per-contact detail behind the aggregate, use `GET /runs/{id}/conversations`.

Retrieves a single run by ID, with its lifecycle status and aggregate progress.

## Overview

A run is one agent dialling a list of contacts. It does not replace the conversation, it batches it: launching a run mints **one conversation per contact**, and the call attempts hang off that conversation exactly as they do for a conversation you created on its own.

This endpoint returns the roll-up. For the per-contact detail behind it, use [List Run Conversations](/api-reference/runs/list-run-conversations).

<Info>
  Runs are writable over the API: [create](/api-reference/runs/create-run) one,
  [attach contacts](/api-reference/runs/attach-run-contacts) and
  [launch](/api-reference/runs/launch-run) it now or up to 30 days out. This endpoint and its
  conversations list are how you monitor it afterwards.
</Info>

## Use Cases

* **Monitor a batch**: poll one endpoint for the state of hundreds of calls
* **Correlate**: match a `conversation.*` webhook back to the batch it came from, through the `runId` in its payload
* **Report**: show your users how far a campaign has got without holding call state yourself

## Response Data

```json theme={null}
{
  "id": "789e0123-e45b-67d8-a901-234567890123",
  "name": "Q3 product follow-ups",
  "agentId": "456e7890-e12b-34d5-a678-901234567890",
  "status": "RUNNING",
  "scheduledAt": null,
  "scheduleError": null,
  "progress": {
    "total": 42,
    "queued": 30,
    "inProgress": 3,
    "completed": 8,
    "failed": 1,
    "cancelled": 0,
    "unreachable": 0,
    "completion": 0.21
  },
  "createdAt": "2026-08-20T09:00:00Z",
  "updatedAt": "2026-08-20T11:42:00Z"
}
```

Reading the buckets:

* Every conversation lands in **exactly one** bucket, so the six counts sum to `total`, and `total` is the run's real conversation count. A `DRAFT` run has produced none yet, so every count is `0`.
* `inProgress` counts calls that are **ringing or connected right now**. That is not the same as the conversation's stored `status`, which stays `SCHEDULED` while a call is being placed — such a call is moved out of `queued` rather than added on top, which is why the buckets still sum.
* `unreachable` is its own bucket rather than part of `failed`. Nothing malfunctioned: the retry budget was spent without the contact ever picking up.
* `completion` is the fraction of conversations in a terminal state — `completed + failed + cancelled + unreachable` over `total` — between `0` and `1`. It is `0` on a run that has produced nothing.

## Scheduled runs

`scheduledAt` is when a `SCHEDULED` run will start dialling, and `null` on every run that launched immediately.

`scheduleError` is why a scheduled run did **not** start at its time. A scheduled launch is re-admitted against billing when it fires, and a refusal then has no request to answer — so it is reported here instead. The run stays `SCHEDULED` and is retried, which means resolving the cause is enough to make it go; there is nothing to re-book.

<Warning>
  This field is the only place a failed start is visible. **A run whose `scheduledAt` has passed
  while its `status` is still `SCHEDULED` has been refused**, and if you are not reading
  `scheduleError` it will sit there indefinitely with nobody watching.
</Warning>

## Status

| Status      | What it means                                                    |
| ----------- | ---------------------------------------------------------------- |
| `DRAFT`     | Contacts may be attached; nothing has been dialled               |
| `SCHEDULED` | Booked for `scheduledAt`; nothing dialled until then             |
| `RUNNING`   | Dispatching, or waiting on calls it has dispatched               |
| `PAUSED`    | Stopped, reversibly. Nothing further is dialled until you resume |
| `COMPLETED` | Every conversation has reached a terminal state                  |
| `CANCELLED` | Stopped for good. Nothing further is dispatched                  |

<Warning>
  `COMPLETED` is **not terminal**. Attaching a contact to a finished run reopens it to
  `RUNNING`, which is what makes a run usable as a rolling sequence rather than a one-shot
  batch. Do not treat `COMPLETED` as a signal to stop polling unless you also know nothing more
  will be attached.
</Warning>

## Polling

```javascript theme={null}
async function waitForRun(runId) {
  for (;;) {
    const response = await fetch(`https://api.instaview.sk/runs/${runId}`, {
      headers: { Authorization: `Bearer ${apiKey}` },
      // Without a deadline a stalled request never settles.
      signal: AbortSignal.timeout(10_000),
    });

    if (!response.ok) {
      throw new Error(`Reading the run failed: ${response.status} ${response.statusText}`);
    }

    const run = await response.json();
    if (run.progress.completion === 1) return run;

    await new Promise((resolve) => setTimeout(resolve, 30_000));
  }
}
```

Polling is the fallback, not the recommendation. Each conversation the run produces fires the ordinary [`conversation.*` webhooks](/guides/webhooks), and every one of those payloads carries `runId` — so a handler attributes the call to this run without polling, and without reading the conversation back.

## Company Isolation

You can only read runs belonging to your own API key's company. A run in another company returns `404 Not Found`, the same as one that does not exist — the API does not confirm that a resource you cannot read exists.

## Error Scenarios

* **404 Not Found**: the run does not exist, has been deleted, or belongs to a different company
* **403 Forbidden**: the API key does not hold `read:runs`

## Related Resources

<CardGroup cols={2}>
  <Card title="Runs Resource Guide" icon="layer-group" href="/guides/resources/runs">
    How a run batches conversations
  </Card>

  <Card title="List Run Conversations" icon="list" href="/api-reference/runs/list-run-conversations">
    The per-contact detail behind the aggregate
  </Card>

  <Card title="Conversations Resource Guide" icon="microphone" href="/guides/resources/conversations">
    What each conversation in a run carries
  </Card>

  <Card title="Webhooks" icon="bolt" href="/guides/webhooks">
    Be told about each call instead of polling
  </Card>
</CardGroup>


## OpenAPI

````yaml GET /runs/{id}
openapi: 3.0.0
info:
  title: InstaView API
  description: |-
    InstaView API Documentation

    ## Authentication

    All endpoints require API key authentication using Bearer token:
    ```
    Authorization: Bearer sk_your_api_key_here
    ```

    ## API Key Management

    The API Key module provides comprehensive key management for:
    - **Direct Client Keys**: Company-scoped keys for your applications
    - **ATS Partner Keys**: Resource-scoped keys for ATS integrations

    ### Key Features
    - HMAC-SHA256 hashing for API key storage
    - Configurable rate limiting
    - Comprehensive audit logging
    - Company-level isolation
    - Resource scoping for ATS partners
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.instaview.sk
    description: Production API Gateway
security: []
tags: []
paths:
  /runs/{id}:
    get:
      tags:
        - Runs
      summary: Get run by ID
      description: >-
        Returns one run with its lifecycle status and aggregate progress,
        ensuring it belongs to the API key's company. A run batches
        conversations rather than replacing them: it mints one conversation per
        contact, and `progress` counts those. For the per-contact detail behind
        the aggregate, use `GET /runs/{id}/conversations`.
      operationId: PublicRunsController_getRunById_v1
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
            format: uuid
        - name: companyId
          required: false
          in: query
          description: >-
            Required for ATS API keys to specify which company to access.
            Ignored for standard company API keys.
          schema:
            type: string
      responses:
        '200':
          description: ''
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicRunDto'
      security:
        - bearer: []
components:
  schemas:
    PublicRunDto:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Run ID
          example: 789e0123-e45b-67d8-a901-234567890123
        name:
          type: string
          description: Name of the run
          example: Q3 product follow-ups
        agentId:
          type: string
          format: uuid
          description: The agent this run dials with
          example: 456e7890-e12b-34d5-a678-901234567890
        status:
          type: string
          description: >-
            Lifecycle status. A `DRAFT` run has dialled nothing yet; `COMPLETED`
            is not terminal, because attaching a contact to a finished run
            reopens it to `RUNNING`.
          enum:
            - DRAFT
            - SCHEDULED
            - RUNNING
            - PAUSED
            - COMPLETED
            - CANCELLED
          example: RUNNING
        scheduledAt:
          type: string
          format: date-time
          nullable: true
          description: >-
            When a scheduled run will start dialling, or `null` for one that
            launches immediately. Set together with the `SCHEDULED` status.
          example: '2026-09-15T09:00:00Z'
        scheduleError:
          type: string
          nullable: true
          description: >-
            Why a scheduled run did not start at its time, or `null`. A
            scheduled launch is re-admitted against billing when it fires, and a
            refusal then has no request to answer - it is reported here instead.
            The run stays `SCHEDULED` and is retried, so resolving the cause is
            enough to make it go.
          example: >-
            Insufficient minutes available to schedule 10 interviews (50 minutes
            total). Please purchase additional minutes.
        progress:
          description: >-
            Aggregate progress across the run's conversations. Every
            conversation lands in exactly one bucket, so the six counts sum to
            `total`.
          allOf:
            - $ref: '#/components/schemas/PublicRunProgressDto'
        createdAt:
          type: string
          description: Created timestamp
          example: '2026-08-20T09:00:00Z'
        updatedAt:
          type: string
          description: Updated timestamp
          example: '2026-08-20T11:42:00Z'
      required:
        - id
        - name
        - agentId
        - status
        - progress
        - createdAt
        - updatedAt
    PublicRunProgressDto:
      type: object
      properties:
        total:
          type: number
          description: Conversations this run has produced
          example: 42
        queued:
          type: number
          description: Queued, not yet dialled
          example: 30
        inProgress:
          type: number
          description: Ringing or connected right now
          example: 3
        completed:
          type: number
          description: Finished conversations
          example: 8
        failed:
          type: number
          description: Conversations that failed
          example: 1
        cancelled:
          type: number
          description: Conversations that were cancelled
          example: 0
        unreachable:
          type: number
          description: >-
            Contacts whose retry budget was spent without the call ever
            connecting
          example: 0
        completion:
          type: number
          description: >-
            Fraction of conversations in a terminal state (completed + failed +
            cancelled + unreachable), 0 to 1. `0` on a run that has produced
            nothing yet.
          example: 0.21
      required:
        - total
        - queued
        - inProgress
        - completed
        - failed
        - cancelled
        - unreachable
        - completion
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: API key for authentication using Bearer scheme

````