# Delete a watch

> Soft-cancel a watch so it stops scheduling new runs while preserving its run history.

`DELETE /v1/watches/:id` sets a watch to `canceled`. It does not hard-delete the row or its run history.

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

## Tenant scope

Writes are owner-scoped: another tenant's watch id is `404 WATCH_NOT_FOUND`, never `403`. Restricted (`sk_*`) keys always write to 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 write. Overrides the
  `X-AISearch-On-Behalf-Of` header when both are sent.
</ParamField>

## Request

This endpoint has no request body.

<CodeGroup>

```bash cURL
curl -X DELETE 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',
  {
    method: 'DELETE',
    headers: { Authorization: `Bearer ${process.env.AISEARCH_API_KEY}` },
  },
);
const { watch } = await res.json();
```

```python Python
import os, requests

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

</CodeGroup>

## Response

```json 200 OK
{
  "watch": {
    "id": "watch_8f2c1a7e",
    "status": "canceled"
  }
}
```

<ResponseField name="watch.id" type="string">
  The watch id.
</ResponseField>

<ResponseField name="watch.status" type="string">
  Always `canceled` after the soft delete.
</ResponseField>

<Note>
  A canceled watch stops scheduling new runs. Existing run history stays
  readable with [`GET /v1/watches/:id/runs`](/api-reference/watches/runs).
</Note>

## Errors

<ResponseField name="404" type="WATCH_NOT_FOUND">
  No watch exists for that id, or it belongs to another tenant (reads and writes
  are owner-scoped — 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">
    Lifecycle, scheduling, billing, and auto-pause behavior.
  </Card>
  <Card
    title="Watch runs"
    icon="clock-rotate-left"
    href="/api-reference/watches/runs"
  >
    Read preserved run history after cancellation.
  </Card>
  <Card title="Get a watch" icon="file-lines" href="/api-reference/watches/get">
    Read the watch and its recent runs.
  </Card>
  <Card title="Create a watch" icon="plus" href="/api-reference/watches/create">
    Create a new scheduled query.
  </Card>
</CardGroup>
