---
title: "List watchable boards"
method: GET
path: "/api/v1/boards"
tags: ["Board Watches"]
---

# List watchable boards

`GET /api/v1/boards`

## Request

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

List every board (a tracked corpus source, identified by corpusType + state) available to watch. A board's refresh cadence is fixed by what we already track; watching it does not change how often it refreshes.

Narrow with `corpusType` and/or `state` when you already know what you want to watch, rather than paging the whole registry: `?corpusType=state_regulation&state=tx` is one board, and `?state=federal` is every federal one. `corpusType` is matched case-insensitively, and `state=federal` selects the boards that have no state.

`total` is the number of boards matching your filters BEFORE paging, and `hasMore` is true when another page exists, matching the paging contract on `/us/statutes/search` and the change feeds.

`lastRetrievedAt` says when we last pulled that source from its publisher. Read it together with `cadence` before treating silence on a watch as 'nothing changed'.

`publishesSourceChangedOn` says whether this board's change events can carry the publisher's own date for a change. It is false on most boards, and there it means the date is never present rather than sometimes missing, so check it before writing code that waits for `sourceChangedOn` to appear. True today on `cfr`, `federal_rules` only.

**Free.** Requires an API key and is rate-limited, but costs no credits.

## Query parameters

- `corpusType` string, nullable: Only boards for this corpus type, matched case-insensitively so the uppercase spelling used by the statutes endpoints (`CFR`) finds the board (`cfr`). An unknown value is an empty page with `total: 0`, not an error.
- `state` 'federal' | 'al' | 'ak' | 'as' | 'az' | 'ar' | 'ca' | 'co' | 'ct' | 'de' | 'dc' | 'fl' | 'ga' | 'gu' | 'hi' | 'id' | 'il' | 'in' | 'ia' | 'ks' | 'ky' | 'la' | 'me' | 'md' | 'ma' | 'mi' | 'mn' | 'ms' | 'mo' | 'mt' | 'ne' | 'nv' | 'nh' | 'nj' | 'nm' | 'ny' | 'nc' | 'nd' | 'mp' | 'oh' | 'ok' | 'or' | 'pa' | 'pr' | 'ri' | 'sc' | 'sd' | 'tn' | 'tx' | 'ut' | 'vt' | 'vi' | 'va' | 'wa' | 'wv' | 'wi' | 'wy', nullable: Only boards for this jurisdiction. Pass `federal` for the boards that have no state (USC, eCFR, the Federal Register). Omit for no jurisdiction filter -- which is NOT the same as `federal`.
- `limit` integer: Max boards to return. The default covers the whole registry today; check `total` rather than assuming it always will.
- `offset` integer: Number of boards to skip, for paging.

## Response `200`

The list of watchable boards.

- BoardsEnvelope
  - `data` BoardsPage, required
    - `boards` BoardResponse[], required
      - `corpusType` string, required
      - `state` string, nullable
      - `label` string, required
      - `cadence` string, required
      - `scopable` boolean: Whether POST /watches accepts a HIERARCHY scope (title/chapter/part/section) for this source. False for sources whose documents are not citations (a Federal Register act_id is `EXEC_2026-11595`), so there is no title or part to narrow by; sending a hierarchy scope to one of those returns 400. This does NOT gate the exact-section form: `{"actId": ...}` is accepted on every source, and is the only way to narrow one where this flag is false.
      - `sourceScopable` boolean: Whether POST /watches accepts a NAMED-SOURCE scope (`{"source": "fdic_fil"}`) for this board. A separate flag from `scopable` above, which means the hierarchy form specifically: the two are close to opposites in practice. `agency_guidance` accepts a source and no hierarchy; `state` accepts a hierarchy and has no named sources at all. The pickable values are in `sources` below.
      - `agencyScopable` boolean: Whether POST /watches accepts an AGENCY scope (`{"agency": "irs"}`), which covers every source that publisher issues on this board. False where the named sources carry no publishing agency: the FAR/DFARS split on `cfr` is a procurement-system split, and the rules of procedure are promulgated by the courts. An agency scope is expanded when a change event is matched, not when the watch is created, so a source registered after your watch is covered by it automatically. The pickable values are in `agencies` below.
      - `sources` ScopeChoice[], nullable: The named sources a `source` scope may use ON THIS BOARD, as `{code, name}`. Deliberately narrower than the `source` filter published on `POST /us/statutes/search`: `agency_guidance` and `agency_manuals` are two boards reading one corpusType, and a scope naming a source the OTHER board emits is accepted and then permanently silent. Omitted when `sourceScopable` is false.
        - `code` string, required: The value to send in `scope`.
        - `name` string, required: Human-readable name, for a picker label.
      - `agencies` ScopeChoice[], nullable: The agencies an `agency` scope may name on this board, as `{code, name}`, restricted to publishers that actually issue something here. Omitted when `agencyScopable` is false.
        - `code` string, required: The value to send in `scope`.
        - `name` string, required: Human-readable name, for a picker label.
      - `scopeBrowseCorpus` string, nullable: The `corpusType` to pass to `GET /us/statutes/divisions` to enumerate this source's titles, chapters and parts for a scope picker. Deliberately NOT the same vocabulary as `corpusType` above: a board is `cfr`, /divisions wants `CFR`. Null means the source is scopable but has no hierarchy browser, so offer a free-text scope input instead of a cascading picker.
      - `lastRetrievedAt` string, nullable: ISO-8601 UTC timestamp of the last refresh run that pulled this source from its publisher and finished cleanly. A run that found nothing new counts: it still confirmed the source on that date, and for a watch that is the useful signal (no alert since then means no change, not a stalled pipeline). Omitted when we have no confirmed run to point at, which means UNMEASURED, never healthy. Same value `/us/statutes/coverage` reports for the same body of law, from the same service. Read it together with `cadence`: it is the only freshness signal this object carries, and it is a date, not a verdict. A date more than one cadence period old (a `monthly` board last retrieved two months ago) means at least one scheduled run did not confirm the source, so silence on a watch for that board is uninformative rather than evidence of no change.
      - `publishesSourceChangedOn` boolean: Whether change events on this board can carry `sourceChangedOn`, the PUBLISHER's own date for the change, as opposed to `detectedAt`, which is when our refresh saw it. Read this BEFORE building on that field. Change events omit `sourceChangedOn` entirely when it is unknown, so on a board where this flag is false its absence says nothing about the publisher: it means we do not carry a per-section date from that source at all, on any event, and no amount of waiting produces one. Today that is every board except `cfr`, `federal_rules`. True does not promise the date on every event either. Even where we do carry it, the publisher exposes it for some sections and not others, and a `removed` section has no date by construction. Absent always means UNKNOWN. Do not substitute `detectedAt`, which can trail the real amendment by months.
      - `changeSignal` string: How this board's source publishes change, which is a different question from how recently we pulled the source and has to be read alongside it. `continuous`: the publisher revises this body of law as it changes, and a refresh that finds a revision emits a change event. Silence on a `current` board means nothing changed. `edition_only`: the publisher issues this body of law as periodic EDITIONS, and we can only detect a new edition arriving. Between editions there is no change signal at all, so silence means only that no new edition has been published. It is NOT evidence that the underlying law is unchanged, and on a slow-cadence board it can be silent for a year or more while the law moves. Read the section payload's own `currentThrough` to see how current the text you are being served actually is.
    - `total` integer, required: Boards matching your filters, before paging.
    - `hasMore` boolean, required
  - `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 HIGHEST change `id` on the page, null on an empty page. Send it back as `sinceId`.
    - `hasMore` boolean, nullable: Change feeds only: true when the page filled to `limit`.

## Other responses

- `401`: Invalid or missing API key.
- `403`: API key lacks `research:read` scope.
- `422`: Validation error: `detail` plus one `errors` entry per rejected field.
- `429`: Rate limit exceeded.

---

[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/fbac9b87775e?raw)
