---
title: "Update a board watch"
method: PATCH
path: "/api/v1/watches/{watch_id}"
tags: ["Board Watches"]
---

# Update a board watch

`PATCH /api/v1/watches/{watch_id}`

## Request

- Base URL: `https://api.vaquill.ai`
- URL: `https://api.vaquill.ai/api/v1/watches/{watch_id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`
- TypeScript: <https://skmtc.dev/vaquill/apis/vaquill-developer-api/docs/api/v1/watches/:watch_id/patch.ts> (a function with typed inputs; its response is checked against the schema)

Partially update a watch you own. Omitted fields are left unchanged. Use `isActive: false` to pause and `isActive: true` to resume. A paused watch is skipped by every future notification but keeps its history and config. `webhookUrl` (webhook/both channel) and `emailAddress` (email/both channel) can be rotated, but not cleared. `webhookSecret` can be rotated, or cleared by sending an empty string `""`, which stops signing deliveries; `null` is refused. None of them can be set on a watch whose channel does not use them. `isActive` must be a boolean: `null` is refused with a 422 rather than read as false. To change channel itself, delete and recreate the watch.

Free.

## Path parameters

- `watch_id` string, required: Id of the watch, as returned by `POST /watches` (`id`).

## Request body

- UpdateWatchRequest
  - `isActive` boolean, nullable: Pause (false) or resume (true) the watch. `null` is refused with a 422.
  - `webhookUrl` string, nullable: New webhook URL. Only valid on a webhook/both channel watch. Re-validated against the SSRF blocklist. Cannot be cleared.
  - `webhookSecret` string, nullable: New signing secret, or an empty string to stop signing deliveries (the one clearable field; `null` is refused with a 422). Only valid on a webhook/both channel watch.
  - `scope` object, nullable: Optional narrowing so this alert covers one citation instead of an entire source. Four mutually exclusive forms. Omit entirely to watch the whole source. Hierarchy prefix: keys `title`, `chapter`, `part`, `section`, e.g. `{"title": "21", "part": "314"}` for 21 CFR part 314. Every level you set must match. `title` is required whenever any narrower level is set, and `section` also needs `chapter` or `part`. Sources without a title/chapter/part hierarchy return 400 (see `scopable` on `GET /boards`). Exact section: `{"actId": "CFR_T21_P314_S314_50"}`, using the `actId` from search results and change events. Case-sensitive and validated at create time: an act_id we do not hold, or one from a different source, is a 400. Works on every source, and is the only way to follow a single Federal Register document. Named source: `{"source": "fdic_fil"}`, for corpora that fold several independent bodies of law behind one `corpusType`. The `agency_guidance` board alone carries 47 named sources across 24 agencies, so an unscoped watch on it delivers FDIC letters, IRS notices, OFAC FAQs and DOE appliance standards together. Accepted on `agency_adjudication`, `agency_guidance`, `agency_manuals`, `cfr`, `federal_rules`; anything else returns 400. Pickable values are on the board's `sources` array in `GET /boards`. Publishing agency: `{"agency": "irs"}`, covering every source that agency issues on the board (the IRS alone publishes 5 named series). Expanded when an event is matched, not when the watch is created, so a source registered later is covered automatically. Accepted on `agency_adjudication`, `agency_guidance`, `agency_manuals`; pickable values are on the board's `agencies` array in `GET /boards`.
  - `emailAddress` string, nullable: New email address. Only valid on an email/both channel watch. Cannot be cleared.
  - `webhookAuth` WebhookAuthRequest: How a delivery should authenticate itself to your endpoint. SEPARATE FROM `webhookSecret`, and the distinction is the point. `webhookSecret` signs the body so you can prove it is intact and ours. This sends a credential so your gateway can reject anything else before it reaches your handler. Most integrations want the second, many want both, and the two are set independently.
    - `scheme` 'none' | 'bearer' | 'basic' | 'header': `bearer` sends `Authorization: Bearer <secret>`. `basic` sends `Authorization: Basic <secret>` with the secret already base64-encoded by you. `header` sends `<headerName>: <secret>`, for gateways that read something like `X-Api-Key`. `none` removes any credential currently stored.
    - `secret` string, nullable: The credential value. Stored encrypted and never returned. Required when setting a scheme for the first time or changing scheme; on PATCH you may omit it to keep the stored one while changing only `headerName`.
    - `headerName` string, nullable: Header to send the credential on. Required for `header`, and rejected for every other scheme. Cannot be `Authorization` (use `bearer`/`basic`), a transport header, or one of ours.

## Response `200`

The updated watch.

- WatchEnvelope
  - `data` WatchResponse, required
    - `id` string, required
    - `corpusType` string, required
    - `state` string, nullable
    - `channel` string, required
    - `webhookUrl` string, nullable
    - `emailAddress` string, nullable
    - `scope` object, nullable
    - `isActive` boolean, required
    - `createdAt` string, required
    - `updatedAt` string, nullable
    - `lastNotifiedAt` string, nullable
    - `lastStatus` integer, nullable
    - `webhookAuth` WebhookAuthResponse: Auth CONFIG as read back. Never includes the credential itself.
      - `scheme` string, required
      - `headerName` string, nullable
      - `hasSecret` boolean
    - `cadence` string, nullable: How often we poll this board's source: `daily`, `weekly`, `monthly` or `annual`. Same value as `GET /boards`. Watching does not change it, and checking `/changes` more often than this gains nothing.
    - `lastRetrievedAt` string, nullable: ISO-8601 UTC timestamp of the last refresh run for this board that finished cleanly. A run that found nothing new counts.
    - `changeSignal` string: `continuous` or `edition_only`. On an `edition_only` board we can only detect a new edition arriving, so silence on this watch means no new edition, not that the law is unchanged. Full definition on `GET /boards`.
  - `meta` ResponseMeta, required: The `meta` block every board-watch route returns beside `data`.
    - `processingTimeMs` number, required
    - `creditsConsumed` number, required
    - `cursor` integer, nullable: Change feeds only: the value to send back as `sinceId`. Null on an empty page. The highest change `id` on the page, except on a full newest-first page read with a `sinceId`, where unread rows sit below the page and the cursor stays at your `sinceId`; use `nextBeforeId` to reach them.
    - `nextBeforeId` integer, nullable: Change feeds only, full `order=desc` pages: the lowest change `id` on the page. Send it as `beforeId` for the next older page. Null otherwise.
    - `hasMore` boolean, nullable: Change feeds only: true when the page filled to `limit`.

## Other responses

- `400`: Invalid update (field does not apply to this channel, a rejected webhook target, or an invalid scope).
- `401`: Invalid or missing API key.
- `403`: API key lacks `research:read` scope, or the plan does not include webhook delivery (Business only). Repointing a webhook is the same entitlement as creating one.
- `404`: Watch not found.
- `409`: The new scope collides with another watch you already hold on this board and channel.
- `422`: Validation error: `detail` plus one `errors` entry per rejected field.
- `429`: Rate limit exceeded.
- `500`: Internal error (`internal_error`, retryable). Any credits charged for the call are refunded; retry with backoff and quote `requestId` to support if it persists.

## Changes

- **2026-11-07** `340c0d24d0b6`: 65 info
  - added the non-success response with the status `500`
  - added the optional property `candidateCount` to the response with the `400` status
  - added the optional property `candidateCount` to the response with the `401` status
  - added the optional property `candidateCount` to the response with the `403` status
  - …61 more

[Operation history](https://skmtc.dev/vaquill/apis/vaquill-developer-api/changes/api/v1/watches/:watch_id/patch.md)

---

[API](https://skmtc.dev/vaquill/apis/vaquill-developer-api.md) - [All operations](https://skmtc.dev/vaquill/apis/vaquill-developer-api/llms.txt) - [OpenAPI document](https://skmtc.dev/vaquill/apis/vaquill-developer-api/revisions/340c0d24d0b6?raw)
