# Get a watch

> Read one scheduled watch with its current lifecycle state and ten most recent runs.

`GET /v1/watches/:id` returns one watch plus its most recent runs, newest first.

<ParamField path="id" type="string" required>
  Watch id (`watch_...`).
</ParamField>

## Tenant scope

Reads are owner-scoped: another tenant's watch id is `404 WATCH_NOT_FOUND`, never `403`. Restricted (`sk_*`) keys always read their own owner. Internal keys can act on behalf of one tenant for watch reads **and writes** with `?owner=<ownerId>` or `X-AISearch-On-Behalf-Of: <ownerId>`; the query parameter wins when both are present. A restricted key's override is ignored.

When an override is applied, the response adds a top-level `owner` field and an `X-AISearch-Owner` header containing the enforced owner id.

<ParamField query="owner" type="string">
  Internal keys only. Owner id to enforce for this read. Overrides the
  `X-AISearch-On-Behalf-Of` header when both are sent.
</ParamField>

## Request

<CodeGroup>

```bash cURL
curl https://api.aisearchapi.dev/v1/watches/watch_8f2c1a7e \
  -H "Authorization: Bearer $AISEARCH_API_KEY"
```

```javascript Node
const res = await fetch(
  'https://api.aisearchapi.dev/v1/watches/watch_8f2c1a7e',
  { headers: { Authorization: `Bearer ${process.env.AISEARCH_API_KEY}` } },
);
const { watch, runs } = await res.json();
```

```python Python
import os, requests

res = requests.get(
    "https://api.aisearchapi.dev/v1/watches/watch_8f2c1a7e",
    headers={"Authorization": f"Bearer {os.environ['AISEARCH_API_KEY']}"},
)
body = res.json()
watch, runs = body["watch"], body["runs"]
```

</CodeGroup>

## Response

```json 200 OK
{
  "watch": {
    "id": "watch_8f2c1a7e",
    "name": "Startup CRM monitor",
    "query": "best crm for startups",
    "surfaces": ["chatgpt", "perplexity"],
    "regions": [{ "country": "US" }],
    "extract": { "targets": ["HubSpot", "attio.com"] },
    "webhookUrl": "https://example.com/hooks/aisearch",
    "schedule": { "every": "1d", "intervalMinutes": 1440 },
    "status": "active",
    "pausedReason": null,
    "nextRunAt": "2026-07-12T14:00:00Z",
    "lastRunAt": "2026-07-11T14:00:00Z",
    "lastJobId": "job_8t2q",
    "createdAt": "2026-07-01T14:00:00Z"
  },
  "runs": [
    {
      "id": "wrun_2b7d4e9a",
      "watchId": "watch_8f2c1a7e",
      "jobId": "job_8t2q",
      "scheduledFor": "2026-07-11T14:00:00Z",
      "status": "dispatched",
      "detail": "search job dispatched",
      "createdAt": "2026-07-11T14:00:01Z"
    }
  ]
}
```

<ResponseField name="watch" type="object">
  The public Watch object, including its query, surfaces, regions, extraction
  config, webhook URL, normalized schedule, lifecycle state, and timestamps.
</ResponseField>

<ResponseField name="runs" type="object[]">
  Up to **10** most recent runs, newest first. Use [`GET
  /v1/watches/:id/runs`](/api-reference/watches/runs) for full history.

  <Expandable title="run">
    <ResponseField name="id" type="string">Run id (`wrun_...`).</ResponseField>
    <ResponseField name="watchId" type="string">Owning watch id.</ResponseField>
    <ResponseField name="jobId" type="string | null">Created parent search job, or `null` when skipped.</ResponseField>
    <ResponseField name="scheduledFor" type="string">Tick this run represents, ISO-8601.</ResponseField>
    <ResponseField name="status" type="string">`dispatched`, `skipped_credits`, `skipped_limit`, or `failed`.</ResponseField>
    <ResponseField name="detail" type="string">Human-readable outcome detail.</ResponseField>
    <ResponseField name="createdAt" type="string">Run-row creation time, ISO-8601.</ResponseField>
  </Expandable>
</ResponseField>

<Tip>
  For a `dispatched` run, read its `jobId` with [`GET
  /v1/jobs/:id`](/api-reference/get-job) exactly like any other async search.
</Tip>

## Errors

<ResponseField name="404" type="WATCH_NOT_FOUND">
  No watch exists for the given id, or it belongs to another tenant. Reads and
  writes are owner-scoped, so another tenant's id is a `404`, never a `403`.
</ResponseField>

```json 404
{
  "code": "WATCH_NOT_FOUND",
  "error": "no watch with id 'watch_8f2c1a7e'",
  "request_id": "req_9f2c1a7e4b5d48f1a3c6e8d0b2a4f6c8",
  "docs_url": "https://docs.aisearchapi.dev/guides/errors#watch_not_found"
}
```

## Related

<CardGroup cols={2}>
  <Card title="Watches" icon="satellite-dish" href="/guides/watches">
    Scheduling, lifecycle, billing, and run history.
  </Card>
  <Card
    title="Watch runs"
    icon="clock-rotate-left"
    href="/api-reference/watches/runs"
  >
    Page through the complete run history.
  </Card>
  <Card
    title="Update a watch"
    icon="pen-to-square"
    href="/api-reference/watches/update"
  >
    Pause, resume, or change the configuration.
  </Card>
  <Card
    title="Read a job"
    icon="magnifying-glass"
    href="/api-reference/get-job"
  >
    Inspect a dispatched run's parent job.
  </Card>
</CardGroup>
