---
title: "Get many state session laws at once, by id or citation"
method: POST
path: "/api/v1/us/session-laws/batch"
tags: ["US Session Laws"]
---

# Get many state session laws at once, by id or citation

`POST /api/v1/us/session-laws/batch`

## Request

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

Read up to 50 state session laws in one call: the same record
`GET /us/session-laws/{sessionLawId}` returns, for each id or citation in `ids`, in the order you
sent them. Use it to enrich a list (ids from `/us/session-laws/list` or `/us/session-laws/changes`,
or a memo with a dozen session-law citations) without a round trip per law. To identify a citation
without reading the law, `POST /us/statutes/resolve` costs 2 credits per item and answers with
a `sessionLaw` match block (title, dates, source link). This route returns the full record and,
optionally, the first page of the text. It also helps under the default limit of 30 requests per
minute per key (a plan raises it).

**Cost**: 2 credits per law served, the single-lookup price. Batching saves round trips,
not credits. A miss is not charged, and `creditsConsumed` reports what was billed. A citation in
`ids` also pays the `/us/statutes/resolve` price (2 credits) as its own ledger line, as on
`GET /us/session-laws/{sessionLawId}`: kept whenever we gave a verdict (a served law, an unresolved
or ambiguous citation), refunded when the session it points into is only partly collected or when we
failed. An id pays no resolve fee.

**Every entry gets an answer.** A served law is in `laws`; every other entry is in `notFound` with a
`status`, the finer `reason` the single route's 404 carries, the same `detail` sentence, and the
candidates where there are any. Every distinct entry is in `laws`, in `notFound`, or, when it names
a law an earlier entry already produced, in `resolved`, so a shorter `laws` array can always be
explained.

**Mapping your inputs.** `laws` holds only the laws served, so it cannot be zipped back onto `ids`
by position. Each law carries the `input` it answers, and `resolved` lists every input that did not
match an id exactly as sent (a citation, or an id cleaned of whitespace, quotes or a trailing
period) with the id it resolved to. Duplicates are collapsed first: an entry identical to an earlier
one after trimming is dropped, order is kept, and `deduped` says how many. Two different spellings of
one law (`S.F.No. 1552` and its `sessionLawId`) serve the law once, under the first, bill it once,
and list both in `resolved`.

| `status` | Meaning |
| --- | --- |
| `resolved` | Served. |
| `not_held` | Served as a record: the registry knows the law and holds no text (`textStatus: not_held`). |
| `not_found` | No law carries the id. |
| `unparsed` | Reads as a citation no state session law we hold carries. |
| `ambiguous` | The citation names several laws, all in `didYouMean`, none chosen (Minnesota 2025 has two Chapter 1s). |
| `needs_jurisdiction` | A citation form several states share, naming none: send `jurisdiction`. |
| `session_not_fully_collected` | Nothing matched in a session we have only partly collected, so the law may exist. Not charged, resolve price included. |
| `federal` | Federal acts are read at `/us/statutes/section`. |
| `error` | We failed to look this entry up. Says nothing about the law, is refunded in full, and is safe to resend. |

`jurisdiction` scopes how every citation in the batch is read, as on the single route. It is
validated before anything is charged: a bad code is a 422.

`includeBody` adds the first page of each served law's text (about 30,000 characters) as
`body`, at the body price (6 credits) per law whose page is served, charged after the work
because the count is not knowable up front. It multiplies with the batch: 50 laws at
2 + 6 is 400 credits in one call. A law whose text is withheld, not held or
empty returns `body: null` and is not charged for it. If your balance cannot cover the pages after
the records were served, the records are returned without bodies rather than taking the paid-for
result away. `bodyNextCursor` continues a longer act on `GET /us/session-laws/{sessionLawId}/body`.

**Limits.** At most 50 distinct entries after duplicates collapse (a raw list of up to 200
is accepted so a run of repeats is not refused), each at most 300 characters. An empty list,
an over-long entry, more than 50 distinct entries or a bad `jurisdiction` is a 422 and is not
charged. At most 8 lookups run at once inside a call.

**Example**

```bash
curl -X POST "https://api.vaquill.ai/api/v1/us/session-laws/batch" \
  -H "Authorization: Bearer $VAQUILL_API_KEY" -H "Content-Type: application/json" \
  -d '{"ids": ["SSL_MN_2025R_G_Y2025_C1", "S.F.No. 1552"], "jurisdiction": "mn"}'
```

```javascript
const res = await fetch("https://api.vaquill.ai/api/v1/us/session-laws/batch", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VAQUILL_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ ids: ["SSL_MN_2025R_G_Y2025_C1", "S.F.No. 1552"], jurisdiction: "mn" }),
});
const { laws, notFound, resolved } = await res.json();
const byInput = new Map(laws.map((law) => [law.input, law]));
```

**Related endpoints**

- `GET /us/session-laws/{sessionLawId}` is the single read, with the same record and rules.
- `GET /us/session-laws/list` and `GET /us/session-laws/changes` are where the ids come from.
- `GET /us/statutes/resolve` points a session-law citation here.

**Nulls.** Every response field is present: one with no value is `null` (`[]` for a list). The
examples here leave the nulls out.

**Rate limits.** Calls count against your key's per-minute budget like every Data API route; a 429
carries `Retry-After`.

## Headers

- `Idempotency-Key` string, nullable: Optional. 16 to 255 visible ASCII characters (a UUIDv4 works). Repeating the same request with the same key replays the original 2xx response for 24 hours without charging again. The same key on a different request is rejected. With the account's `cacheQueryDerivedData` retention setting off, no body is stored and a retry answers 409 `idempotency_replay_unavailable`, still without a second charge.

## Request body

- SessionLawBatchRequest: Batch read. See `POST /us/session-laws/batch`.
  - `ids` string[], required: State session law ids, or citations, to read: up to 50 DISTINCT entries per call. Each entry is read exactly as the `{sessionLawId}` path of `GET /us/session-laws/{sessionLawId}` reads one: an id as sent, an id carrying copy damage, or a citation (`Minn. Laws 2025, ch. 1`, `P.A. 104-0001`, `S.F.No. 1552`). Entries are trimmed, and blank ones are dropped. Duplicates collapse FIRST (the first spelling wins, order is kept) and the cap applies to what is left, so a list quoting one law sixty times is one entry; `deduped` says how many were collapsed. 200 is the ceiling on the raw list. An entry is at most 300 characters. Federal ids (`SAL_...`) and endpoint names are misses, never charged. A CITATION also pays the resolve price (2 credits) whether it resolves or not, because the lookup is the verdict: an unresolved, ambiguous or state-less citation keeps it. It is refunded only when the session is partly collected or we failed. An id never pays it.
  - `jurisdiction` '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: Optional two-letter state code that scopes how a CITATION in `ids` is read, for the whole batch: it supplies the state a citation does not name (`Laws 2025, ch. 1` with `mn` is Minnesota's) and vetoes a state the citation does name or whose form belongs to another. Ignored for an id. Takes the 56 jurisdictions (the 50 states, `dc` and the territories `pr`, `gu`, `vi`, `as`, `mp`), case-insensitive; `federal` or an unknown code is a 422 and nothing is charged. Omit it for a batch whose citations each name their own state.
  - `includeBody` boolean: Return the FIRST page of each served law's text inline, on `body`, beside the record. A page is about 30,000 characters and costs the ordinary body price (6 credits) per law whose page is served; a law whose text is withheld, not held or empty comes back with `body: null` and is not charged for it. Read `creditsConsumed` rather than computing the total: the worst case is 50 laws at 2 + 6 credits each. `bodyNextCursor` continues a longer act on `GET /us/session-laws/{sessionLawId}/body`.

## Response `200`

One entry per distinct id or citation: the served laws in `laws`, every other entry in `notFound` with its status and reason. Not every entry is a law: read `notFound`, and `creditsConsumed` for what was billed.

- SessionLawBatchResponse: Response for `POST /us/session-laws/batch`.
  - `laws` SessionLawBatchLaw[]: The served laws, one per distinct law, in the order the entries of `ids` first reached them. Entries that missed are NOT here, so a client mapping by position must use `input` on each law (or `notFound`), never the index.
    - `sessionLawId` string, required: Permanent identifier of the law, the key to use everywhere. Shape `SSL_{state}_{session code}_{series}[_Y{numberingYear}]_{C<chapter>|B<billKey>}`. It never changes: a correction to our reading of a law keeps the old id working. Pass it to `GET /us/session-laws/{sessionLawId}`.
    - `lawId` string, nullable: The law's identifier in the open us1 scheme. Null until its identity is confirmed by a second source and the us1 state shape is minted, so it is null on every state law today. Use `sessionLawId`, which is always present.
    - `jurisdiction` string, required: Lowercase two-letter code of the state, `dc` or `pr`. Federal acts are not served by this family: they are on `/us/statutes/section`.
    - `citation` string, required: The act's citation as its publisher prints it, falling back to `{session label}, ch. {number}` when none is printed. It is NOT unique: many states print a bare `CHAPTER 1` every session. Key on `sessionLawId`.
    - `citableAs` string, nullable: The law cited the way a lawyer writes it, from the state's own form: `Minn. Laws 2025, ch. 1`, `2025 Fla. Laws ch. 3`, `Ill. Pub. Act 104-0001`, `S.L. 2025-12` (North Carolina), `Stats. 2025, ch. 12` (California), `Ohio S.B. 1 (2025)` for a state that numbers no chapters. A law in a special or extraordinary session carries it (`Minn. Laws 2025, 1st Spec. Sess., ch. 1`). Every value is read back through the grammar that `GET /us/session-laws/{sessionLawId}` accepts a citation in, and must name this law; one that would not is null, never guessed. Null where the state's form is not known, for a series with no standard form (resolutions, memorials), or for a law with neither a chapter nor a bill key. Where a regular and a special session each have a chapter 1, the bare form is the regular session's law and resolves with that law flagged as the default; the special session's carries its session. Distinct from `citation`, which is the publisher's printed form.
    - `citationShort` string, nullable: A compact label for tables and badges: `MN ch. 1 (2025)`, `IL P.A. 104-0001`, `OH S.B. 1 (2025)`. Not a form to send back: use `citableAs` or the `sessionLawId`. Null exactly when `citableAs` is null.
    - `session` SessionLawDetailSession, required: The session block of a single law: the session, and whether we hold all of it.
      - `code` string, required: Session code, `{year}{type}{ordinal}`. `type` is `R` regular, `S` special, `X` extraordinary, `F` fiscal, `V` veto, `U` unknown. A regular session has no ordinal (`2025R`); a numbered special session carries it (`2025S1`, the first special session of 2025); a lettered one carries its letter (`2025SC`, Florida's Special Session C). `year` is the year the publisher numbers the session by, which for a period spanning two years is the first (District of Columbia Council Period 25 is `2023R`). Pass it as `session` to `GET /us/session-laws/list`.
      - `label` string, nullable: The session's canonical label, as the publisher names it.
      - `type` string, nullable: `regular`, `special`, `extraordinary`, `fiscal`, `veto` or `unknown`.
      - `year` integer, nullable: The year the session convened, the same year `code` starts with.
      - `coverageStatus` 'complete' | 'partial', nullable: Whether we hold every law of this session. `complete`: every law the publisher lists for the session is accounted for, so a law absent from the list does not exist. `partial`: the collection of the session stopped short, so a law that is not found may exist, and this law's neighbours may be missing. The same verdict, with the counts behind it, is in the `sessionLaws` block on `GET /us/statutes/coverage`. Omitted when it cannot be read.
    - `series` string, required: The numbering series the law belongs to within its session. Most states have one, `general`. Others number acts, resolutions or local laws separately (`public`, `act`, `acts`, `law`, `public_act`, `resolve`, `resolution_chapter`, `local`, ...). An open list that grows as jurisdictions load. Filter with `series` on the list.
    - `instrumentType` string, required: What kind of measure this is: `act`, `joint_resolution`, `concurrent_resolution`, `resolution`, `resolve`, `memorial` or `other`. An open list. A resolution that was numbered and published among the session laws is included, with `isLaw` saying whether it binds as law.
    - `number` string, nullable: The chapter or act number exactly as printed, as a string. It is not always an integer: `1`, `2025-12` (Florida), `104-0001` (Illinois), `1A`. Null where the state does not number its acts (see `billKey`).
    - `billKey` string, nullable: Normalised bill identifier (chamber and type letters plus the number) that stands in for a chapter number in states that do not number their acts (Missouri, Ohio, Nebraska). `House Bill 2` is `HB2`. Null whenever `number` is set. Part of the `sessionLawId` as `B<billKey>`.
    - `billNumber` string, nullable: The bill the act originated as, as the publisher prints it. Matches as a citation on `GET /us/session-laws/{sessionLawId}`.
    - `numberingYear` integer, nullable: The year of the numbering sequence the chapter number belongs to, where the state numbers by year (Minnesota, Florida, Texas). It appears in the `sessionLawId` as `_Y2025`. A chapter number is only unique within a session and numbering year: Minnesota's regular and first special sessions of 2025 each have a Chapter 1. Null where one sequence runs across the session (Louisiana).
    - `title` string, nullable: The act's long title as printed, usually beginning `An act relating to`. It names the code sections the act amends in prose.
    - `shortTitle` string, nullable: The act's short title when the publisher gives one (Ohio, New York, the District of Columbia and a few others do), otherwise null.
    - `approvedDate` string, date, nullable: Date the governor (or the equivalent authority) approved the act, ISO 8601. Never an effective date: an act is usually in force on a different day, which is `effectiveDates`. Null when the publisher prints no approval date. Where the registry holds none but the publisher's own dated label on `otherDates` names the governor's signature, it is filled from that label and `approvedDateDerived` is true. The `approvedFrom` and `approvedTo` filters do NOT match a derived date: they read the registry's own approval date.
    - `approvedDateDerived` boolean: True only when `approvedDate` was not held as an approval date and we filled it from a dated label printed on the act (today South Dakota's `Signed by the Governor`, listed under `otherDates`), on an act whose `enactmentOutcome` is `signed` or `line_item_veto`. False when `approvedDate` is null or is the registry's own. We never read a `presented` or `passed` date as an approval, nor a signing label on an act that became law without signature.
    - `effectiveFirst` string, date, nullable: Earliest of the act's effective dates we hold. Null when we hold none: a date the publisher does not print, or prints as a relative rule (`the day following final enactment`), is not guessed. The full list is `effectiveDates` on `GET /us/session-laws/{sessionLawId}`.
    - `effectiveLast` string, date, nullable: Latest of the act's effective dates we hold. Equal to `effectiveFirst` for an act with one date; null when we hold none.
    - `enactmentOutcome` string, required: How the measure became, or failed to become, law. `signed`; `became_law_without_signature`; `veto_overridden`; `line_item_veto` (signed with some items vetoed); `vetoed` and `pocket_veto` (not law); `not_presented` (no governor action recorded, usual for resolutions); `approved_by_voters`; `unknown` (the publisher does not say).
    - `isLaw` boolean, nullable: True for an act that is law. False for a numbered measure that is not: a vetoed bill, a pocket veto. Null when `enactmentOutcome` does not settle it (`not_presented`, `unknown`).
    - `textStatus` 'held' | 'withheld' | 'not_held' | 'pending', required: Whether we serve this law's text. `held`: the text is served by `/us/session-laws/{sessionLawId}/body`. `withheld`: we hold the text but a measured defect keeps it from being served, and `withheldReason` says what. `not_held`: we know the act exists and do not hold its text. `pending`: collected and not yet verified.
    - `withheldReason` string, nullable: Present only when `textStatus` is `withheld`: a plain sentence saying what is wrong with the text we hold and what would release it. Free text, not an enum: show it, do not branch on it. The record itself (dates, sources, title) is still served and still correct.
    - `charCount` integer, nullable: Length of the law's full text in characters, the same as `totalChars` on the body. Null when there is no text. It is reported for a withheld law too (a fact about the text we hold), though that text is not served.
    - `estimatedBodyPages` integer, nullable: The most body pages the text can take, so the price of reading the whole law is at most this times the body price. A page holds up to 30,000 characters but is cut back to a paragraph break, so it can be as short as 24,001; the estimate counts every page but the last at that shortest size, so a long act usually takes fewer pages than this and never more. Text that fits one page is 1. Present when the text can be read: `textStatus` is `held`, or `withheld` for a reason we can label (read it with `includeUnverified=true` on `/body`). Null otherwise. Reading a whole law costs `estimatedBodyPages` times the price of one body page (6 credits per page on `GET /us/session-laws/{sessionLawId}/body`); most acts are a page or two.
    - `textSha256` string, nullable: SHA-256 (hex) of the full text of this law. It changes only when the text does, so it is the cheap way to tell whether a copy you hold is current. Body pages carry the same value.
    - `versionNo` integer, nullable: Revision counter of our record of this law: 1 for the first collection, higher after a re-collection changed the text or the metadata. Not a legislative version.
    - `amendatoryMarkup` string, nullable: Whether the language an amending act strikes and inserts survives in the text. `preserved`: it is in `text`, in the convention `markupConvention` names. `lost`: the publisher printed it and our text does not keep it, so deleted words can read as law: check the source before quoting. `absent`: the act carries no such markup that we found. `not_applicable`: there is no text to carry it.
    - `markupConvention` string, nullable: How preserved markup is written, set only when `amendatoryMarkup` is `preserved`. `wdiff`: deleted language is `[-like this-]` and inserted language `{+like this+}`. `publisher_literal`: the publisher's own words are left as printed (Minnesota prints `new text begin` / `new text end` and `deleted text begin` / `deleted text end` markers). `mixed`: both in one text.
    - `documentKind` string, nullable: What kind of document the text was taken from: `session_law_print` (the publisher's printed chapter), `enrolled_bill`, `slip_law`, `volume_extract` (carved out of a bound volume) or `other`. An open list. Null when there is no text.
    - `identityConfidence` string, required: How firmly the law's identity (session and number) is established. `single_source`: read from one publisher source, which is every state law at launch. `confirmed`: agreed by a second independent source, the level at which a `lawId` can be minted. `inferred`: derived by us rather than printed. `disputed`: sources disagree. The `sessionLawId` is the same at every level.
    - `officialUrl` string, nullable: The PUBLISHER's page for this act, never a Vaquill URL: where a person goes to read the act at its legislature. Where the legislature keeps one page per bill (California, Virginia, New York) it is that page, rebuilt from the session and bill number, so it is present for a law we hold back or only know of. Elsewhere it is the government file the text was collected from (`sourceUrl`), which can be a volume covering many acts. `officialUrlBasis` says which. Null when we hold neither. Our own copy of the text is `GET /us/session-laws/{sessionLawId}/body`, a Vaquill service, and is never reported here.
    - `officialUrlBasis` string, nullable: How `officialUrl` was found: `bill_page` (the publisher's page for this one act) or `text_source` (the government file the text came from, possibly shared by many acts). Null with `officialUrl`.
    - `licenseNote` string, nullable: What the law's licence class is and what it means for reuse, in a plain sentence: `Government public: published by a government body with no restrictive terms, so the text may be reused, including commercially.` Every law served with text is of a class that permits reuse; a note saying otherwise describes a record whose text is held back. Free text to show, not an enum to branch on: branch on `textStatus`.
    - `updatedAt` string, nullable: When this law's record last changed in our registry, ISO 8601 UTC with a `+00:00` offset, the same form as the statutes routes. Use it with `updatedSince` on the list to sync only what changed.
    - `citationAsPrinted` string, nullable: The citation exactly as the publisher prints it. Null when none is printed.
    - `vetoStatusAsPrinted` string, nullable: The publisher's own words on the governor's action. `enactmentOutcome` is our normalised reading of it.
    - `pageCount` integer, nullable: Pages in the source document when it is a PDF. Null for HTML sources.
    - `sourceUrl` string, nullable: The official page or file the act's text was collected from, on a government publisher's host: the first `sources` entry whose `role` is `text` and whose `hostClass` is `gov`. Open it to verify the text against the publisher. Null when we hold no such source (a law we know exists and have not collected) or when the text source is not a government host. Present on a withheld law too: the official copy is always where to go when we hold the text back.
    - `effectiveDates` SessionLawDate[]: Every effective date the publisher prints for the act, in printed order. Always a list, never null; empty when none is held. Empty does NOT mean the act is not in force: a date printed as a rule (`the day following final enactment`) or not printed in the publisher's metadata is not guessed, and the approval date is never substituted for it. An act can take effect in parts, so a date may carry a `scopeAsPrinted`.
      - `kind` string, nullable: What the date is, on `otherDates`: `approved`, `filed` or `other` (`kindAsPrinted` carries the publisher's label for `other`). Null on `effectiveDates`, where every entry is an effective date.
      - `date` string, date, nullable: The date as ISO 8601 when the printed text could be read as one. Null when the publisher's wording is not a calendar date.
      - `dateAsPrinted` string, nullable: The date exactly as the publisher wrote it, including any time of day.
      - `kindAsPrinted` string, nullable: The publisher's own label for what the date is, when it prints one.
      - `scopeAsPrinted` string, nullable: What the date applies to when it is not the whole act, as printed: an act can take effect in parts. Null when the date applies to the act as a whole.
    - `otherDates` SessionLawDate[]: Every other date printed on the act, each with its `kind`: the approval date, filing dates and the publisher's own milestones (presentment to the governor).
      - `kind` string, nullable: What the date is, on `otherDates`: `approved`, `filed` or `other` (`kindAsPrinted` carries the publisher's label for `other`). Null on `effectiveDates`, where every entry is an effective date.
      - `date` string, date, nullable: The date as ISO 8601 when the printed text could be read as one. Null when the publisher's wording is not a calendar date.
      - `dateAsPrinted` string, nullable: The date exactly as the publisher wrote it, including any time of day.
      - `kindAsPrinted` string, nullable: The publisher's own label for what the date is, when it prints one.
      - `scopeAsPrinted` string, nullable: What the date applies to when it is not the whole act, as printed: an act can take effect in parts. Null when the date applies to the act as a whole.
    - `codeSectionsAffected` CodeSectionAffected[]: The code sections the publisher's own table lists the act as affecting, as printed. Always a list. Empty when the publisher prints no such table, which is common: the title still names sections in prose. We do not read sections out of the act text into this list.
      - `sectionAsPrinted` string, required: The code section the act changes, as the publisher's table prints it. Not normalised and not linked to an `actId` on `/us/statutes`.
      - `actionAsPrinted` string, nullable: What the act does to that section, in the publisher's own words or abbreviation (`AMD` amended, `ADD`, `REP`, ...).
      - `codeAsPrinted` string, nullable: The code the section belongs to, as printed.
      - `actSectionAsPrinted` string, nullable: The section of the act itself that makes the change.
    - `sources` SessionLawSource[]: The publisher documents the record was collected from, with the hash and fetch time of each: the audit trail from this response back to the official copy.
      - `sourceIndex` integer, required: Position of this source in the law's source list, starting at 0.
      - `role` string, nullable: What this document supplied: `text` (the act itself), `identity` (the publisher page that lists and numbers the session's laws), `metadata` (dates, veto and status tables), `code_sections` or `certified_image`.
      - `url` string, nullable: The publisher's URL for this document, as we fetched it. Null when the document did not come from a government publisher (`hostClass` `other`) and its host is not one we publish a link to: the document is still archived and `sha256` still describes it, but no link to a third-party host is served.
      - `fetchedAt` string, nullable: When we fetched the document, ISO 8601 UTC with a `+00:00` offset.
      - `contentType` string, nullable: The document's media type as the publisher served it.
      - `sha256` string, nullable: SHA-256 (hex) of the exact bytes we fetched and archived.
      - `byteLength` integer, nullable: Size of the fetched document in bytes.
      - `hostClass` string, nullable: `gov` when the document comes from a government publisher (including an official publisher on a non-`.gov` host), otherwise `other`.
    - `publisher` SessionLawPublisher: What the publisher itself printed or published about an act, beyond the record's dates and citation.
      - `legislatureNumber` integer, nullable: The number of the legislature that enacted the act, as the publisher counts them (Minnesota's 94th Legislature, Alaska's 34th). Null where the publisher does not number its legislatures on the act's own pages; a gap in what we hold, not a fact about the act.
      - `sessionLastYear` integer, nullable: The last calendar year of the session the act belongs to, for a session that spans two (the District of Columbia's Council Period 25 runs 2023 to 2024, California's regular session 2025 to 2026). Equal to `session.year` for a session inside one year.
      - `printedPageStart` string, nullable: The page number printed on the act's first page in the publisher's bound volume, as printed and therefore a string (`1`, `ix`, `42A`). Not the physical page of a PDF: see `provenance.volume`. Null where the act is not printed in a volume.
      - `printedPageEnd` string, nullable: The page number printed on the act's last page, as printed. Null as above.
      - `documentKindAsPrinted` string, nullable: The label the publisher's own document carries for what kind of text it is, exactly as printed: `Enrolled version` (Texas), `As Adopted`, `Pamphlet Law` (New Jersey), `As Enacted`, `slip copy of this session law`. Our normalised reading of it is `documentKind`. Null where the document prints none.
      - `publisherIds` SessionLawPublisherId[]: The identifiers the publisher itself gives the act, in the order it presents them: South Carolina's ratification number, California's `bill_id`, the District of Columbia's act and bill numbers, Maryland's `BillNumber`. Useful for joining to the publisher's own site or data. Which identifiers exist differs by state. Empty when the publisher exposes none.
        - `name` string, required: The publisher's own label for the identifier, exactly as it prints or exposes it, so it is not a vocabulary: `RAT#` (South Carolina), `bill_id` (California), `num type="act"` (District of Columbia), `BillNumber` (Maryland), `L.D.` (Maine).
        - `value` string, required: The identifier's value as the publisher gives it, always a string: `5`, `202520260SB26`, `25-5`, `HB0001`.
      - `otherCitations` string[]: Other citations the publisher prints for the same act, each exactly as printed: `Act No. 1` beside `CHAPTER 1`, `A.L.2025, c.1`, `70 DCR 1863`, `D.C. Act 25-5`. They are accepted as citations on `GET /us/session-laws/{sessionLawId}`. Empty when the publisher prints one form only.
      - `publisherFields` object: The publisher's own structured fields for this act, as the publisher states them and otherwise untouched: an object whose keys, nesting and values are the publisher's own words. The keys DIFFER BY STATE and are not normalised or renamed: Texas gives the bill's full action history with journal page numbers (`Actions`), Maryland the committees and the reading and hearing dates in each chamber, North Carolina and New Mexico a history that can carry vote counts, most states little more than the bill number and a sponsor. What a given state supplies is whatever its publisher printed; do not assume any key exists, and do not read a missing key as a fact about the act. Votes in particular are present only where a publisher printed them. A few values are the publisher's own HTML: treat every string as untrusted text and never render it unescaped. `{}` when the publisher printed no such fields. A value too large to serve is left out and its key named in `publisherFieldsOmitted`.
      - `publisherFieldsOmitted` string[]: Keys of `publisherFields` that exist on the record but were too large to serve inline (past 64 KiB of JSON the largest values are left out, whole, never cut). Typically a publisher's full-bill HTML copy, whose text is on the body route in any case. Empty when nothing was left out, which is almost always.
    - `provenance` SessionLawProvenance: How the text of an act was obtained, and what the collector noted about the record.
      - `textMethod` string, nullable: How the text was extracted from the publisher's document: `pdf_text_layer`, `html`, `xml`, `docx`, `doc`, or `none` when no text was extracted. An open list. `none` is the same fact as `textStatus: not_held` for a collected law.
      - `pagesWithText` integer, nullable: For a PDF, how many of its `pageCount` pages had a text layer to read. A figure below `pageCount` means some pages (a signature page, a scanned stamp) contributed no text. Null for a source that has no pages.
      - `volume` SessionLawVolume: The bound volume an act's text was cut out of.
        - `url` string, required: The publisher's URL of the whole volume (a PDF of every act of the session) that this act's text was cut from. A government host.
        - `pageStart` integer, required: First physical page of the act in that volume, counted from 1 at the first page of the file. Not the page number printed on the page: see `publisher.printedPageStart` for that.
        - `pageEnd` integer, required: Last physical page of the act in that volume, the same counting as `pageStart`.
        - `boundaryHeading` string, nullable: The heading in the volume at which the act's text begins, which is how the cut was found. Null when none is recorded.
      - `caveats` string[]: The collector's own remarks on this record, one string each, verbatim and in order. Most say something about the act or its text that a reader should know: where the chapter number came from when the act does not print one, that the publisher prints no strike-through so there is no amendatory markup to carry, that an effective date is the publisher's wording rather than a calendar date, that the text layer has kerning damage. Some are working notes about how the record was assembled and are published as written; they are free text for a person to read, not a vocabulary to branch on, and their wording can change. Notes that only describe how a page was fetched or decoded are not included. `[]` when there are none.
    - `extrasUnavailable` boolean: Present and `true` only when the read behind `publisher`, `provenance` and `session.coverageStatus` failed on this request. Those three are then absent because we could not read them, not because the act has none: repeat the request to get them. Omitted when the read succeeded.
    - `input` string, required: The entry of your `ids` this law answers, exactly as you sent it (trimmed). When two entries name the same law, the law appears once, under the first.
    - `status` 'resolved' | 'not_held', required: `resolved`: the law is in the registry and its text status is `held`, `withheld` or `pending`. `not_held`: the registry knows the law exists and we hold no text (`textStatus: not_held`); the record is still served, and charged like any other, because it is the answer the lookup was for.
    - `body` string, nullable: The first page of the law's text exactly as printed, present only when `includeBody` was true and the text is served. Null otherwise, and then not charged; `bodyNote` says why. Read `bodyHasMore` to know whether the act continues.
    - `bodyPageEnd` integer, nullable: Character offset just past `body` in the full text: the first page starts at 0. Null when `body` is null.
    - `bodyTotalChars` integer, nullable: Length of the whole text in characters. Null when `body` is null.
    - `bodyHasMore` boolean, nullable: True when the text continues beyond `body`. Each further page is read, and charged, on `GET /us/session-laws/{sessionLawId}/body`. Null when `body` is null.
    - `bodyNextCursor` string, nullable: Send as `cursor` to `GET /us/session-laws/{sessionLawId}/body` to read the next page of this law. Null on the last page, and when `body` is null.
    - `bodyNote` string, nullable: Why `body` is null although `includeBody` was true, as a token: `withheld` or `pending` (the text is not served), `not_held` (we hold no text), `empty_text`, `read_failed` (the read of this law's text failed: not charged, repeat the call or read `/body`), `unaffordable` or `charge_failed` (the bodies could not be paid for, see the response's `bodyNote`). Omitted when `body` is present or `includeBody` was not sent.
  - `resolved` SessionLawResolution[]: One entry per input that did NOT match an id exactly as sent: a citation resolved to its law, or an id cleaned of whitespace, quotes or a trailing period. Includes an input whose law an earlier entry already produced, so every input is mappable onto `laws`. Empty when every entry was an exact id.
    - `input` string, required: What you sent in the path, exactly.
    - `sessionLawId` string, required: The id it resolved to. Send this next time to skip resolution and its fee.
    - `via` 'normalized_id' | 'citation' | 'earlier_entry', required: `citation`: your input was a citation and matched exactly one law's citation form. `normalized_id`: your input was an id carrying surrounding whitespace, quotes or a trailing period, which were removed. `earlier_entry` (batch only): your input was an id exactly as sent, but an earlier entry of `ids` already produced that law, so it appears once in `laws`.
    - `matchedForm` string, nullable: Which of the law's citation forms your input matched: `as_printed` (its printed citation), `bill` (its bill number) or `other_as_printed` (another printed form). Null for `normalized_id`.
  - `notFound` SessionLawBatchMiss[]: Every entry that did not yield a law, in the order sent, each with its `status` and `reason`. A miss is not charged for the route's own price. An entry read as a CITATION also paid the resolve price, kept whenever we gave a verdict on it (`unparsed`, `ambiguous`, `needs_jurisdiction`, `federal`) and refunded on `session_not_fully_collected` and `error`. An id pays no resolve price.
    - `input` string, required: The entry of your `ids`, exactly as you sent it (trimmed).
    - `status` 'ambiguous' | 'needs_jurisdiction' | 'unparsed' | 'session_not_fully_collected' | 'not_found' | 'federal' | 'error', required: `not_found`: no law carries this id (or it exists in another letter case, see `didYouMean`). `unparsed`: it reads as a citation and no state session law we hold carries it. `ambiguous`: the citation names several laws of one state, all in `didYouMean`, none chosen for you. `needs_jurisdiction`: the citation is in a form several states share and names none; `jurisdictions` lists where it exists. `session_not_fully_collected`: nothing matched and the session it points into is only partly collected, so the law may exist; `sessionCoverage` says how much we hold. `federal`: a federal act, served by `/us/statutes/section`. `error`: we failed to look this entry up; it is NOT a statement that the law does not exist, it is refunded in full, and it is safe to send again.
    - `reason` string, required: The finer reason, the same vocabulary as `reason` on the 404 of `GET /us/session-laws/{sessionLawId}`: `not_in_registry`, `wrong_case`, `unresolved_citation`, `ambiguous_citation`, `needs_jurisdiction`, `federal_session_law`, `missing_session_law_id`, `session_not_fully_collected`; or `lookup_failed` when `status` is `error`. Branch on `status`, which is the closed set; the wording of a reason can grow.
    - `detail` string, required: A sentence safe to show a user, the same text the single route's 404 carries.
    - `didYouMean` string[]: Real `sessionLawId`s the entry points at: the one that exists in another case, or every law an ambiguous citation names (at most 20, the conventional reading first). Empty when nothing matched.
    - `defaultSessionLawId` string, nullable: On `ambiguous`, the conventional reading when the registry records one. Informational: it is never served for you.
    - `jurisdictions` string[], nullable: On `needs_jurisdiction`, every state (lower-case postal code) where the citation exists. Name one in the citation, or send `jurisdiction`, and resend. Null otherwise.
    - `candidateCount` integer, nullable: On `ambiguous` and `needs_jurisdiction`, how many laws the citation names in all. When it exceeds `len(didYouMean)` the list is a sample. Null otherwise.
    - `truncated` boolean, nullable: True when `didYouMean` was capped and `candidateCount` is larger. Null otherwise.
    - `sessionCoverage` SessionLawSessionCoverage: One legislative session's session-law coverage.
      - `code` string, required: Session code, for example `2025R`.
      - `label` string, nullable: The session's canonical label.
      - `type` string, nullable: `regular`, `special`, `extraordinary`, `fiscal`, `veto` or `unknown`.
      - `year` integer, nullable: The year the session convened, the year `code` starts with.
      - `status` 'complete' | 'partial', required: `complete` when every law the publisher lists for the session is accounted for. Anything less is `partial`: a law missing from a partial session is not evidence that it does not exist, and asking for one by id or citation answers `session_not_fully_collected`, free of charge, rather than a plain not found.
      - `servedCount` integer, required: Laws from this session we serve: every one we answer for by id, citation or list, whether or not we hold its text (`notHeldCount` of them have none). Laws whose text is withheld are not counted here, they are `withheldCount`. `servedCount + withheldCount` is `registryCount`, less any law still being verified.
      - `withheldCount` integer: Laws from this session we hold and list but whose text is withheld for a measured defect (`textStatus: withheld`). They are real laws: their records are served, their text is not.
      - `notHeldCount` integer: Of the laws counted in `servedCount`, how many have no text held (`textStatus: not_held` or `pending`). A subset of `servedCount`, not an addition to it: do not add it to `servedCount` or `withheldCount`.
      - `registryCount` integer: Every law of this session in our registry, whether or not its text is held: `servedCount + withheldCount`. Any difference is a law still being verified, which is neither.
      - `collectedCount` integer: Laws from this session whose text we have collected, served or withheld. Compare it with `denominator.value` to see how much of the session we hold.
      - `denominator` SessionLawDenominator: How many laws a session is supposed to hold, and where that number comes from.
        - `kind` 'stated_count' | 'complete_listing' | 'max_number' | 'feed_total' | 'our_recount' | 'registry_union' | 'none', required: Where the total comes from. `stated_count`: the publisher states how many measures the session enacted. `complete_listing`: the publisher's own complete list of the session's acts, which we counted. `max_number`: the highest chapter number the publisher printed. `feed_total`: the total a publisher feed reports. `our_recount`: we counted the publisher's pages ourselves. `registry_union`: the measures we know of from several sources. `none`: no total is available, so completeness cannot be judged.
        - `value` integer, nullable: The number of laws the session is expected to hold. Null when `kind` is `none`. Compare it with `registryCount` and `servedCount`.
        - `derivation` string, required: One plain sentence saying what `value` counts and where it comes from. Written for customers: it never contains our internal audit or collection notes.
      - `openGaps` integer: Laws the publisher lists for this session that we could not collect and have not yet. 0 on a `complete` session.
      - `numberingHoles` integer, nullable: Numbers inside the session's printed range that carry no law, which may never have been issued; null when not measured, and never counted in `openGaps`.
      - `denominatorStale` boolean, nullable: True when our registry holds more laws than `denominator.value`, so the figure counts a narrower unit or is out of date and cannot measure what is missing; null when not assessed.
      - `measuredAt` string, nullable: When this session's coverage was last measured, ISO 8601 UTC.
  - `count` integer: Number of laws returned in `laws`.
  - `deduped` integer: How many entries of `ids` were collapsed because an earlier entry was identical after trimming. Zero when none were. Two DIFFERENT spellings of one law are not counted here: the law appears once in `laws` and both spellings are in `resolved`.
  - `bodyNote` string, nullable: Set only when `includeBody` was sent and the bodies were withheld for the whole call: either your balance could not cover them, or the charge for them could not be completed on our side. Either way no body was returned and none was charged, and the laws are intact. Absent otherwise.
  - `creditsConsumed` integer: Credits actually charged for this call, never the list price: 2 per law served, plus the 2-credit resolve price for each citation whose resolution is kept, plus the body price per `body` served. Misses and failures bill nothing for the route.
  - `processingTimeMs` number: Server-side time for this request in milliseconds, excluding network transit. Not billed on.

## Other responses

- `401`: Missing, invalid or revoked API key. Not charged.
- `402`: Insufficient credits for this call. Nothing was done and nothing was charged. Read your balance, free, at `GET /credits/balance`.
- `403`: The API key lacks the `research:read` scope. Not charged.
- `409`: Idempotency conflict. `idempotency_in_progress`: the original request with this key is still running (retry after `Retry-After`). `idempotency_replay_unavailable`: it completed but its response was too large to replay; nothing is charged again, so check the credit balance instead of retrying.
- `422`: A parameter failed validation: `ids` empty, over-long or holding more than 50 distinct entries, `jurisdiction` not a state, or a key the body does not define. Never charged. `errors[].loc` names the parameter exactly as you send it. `idempotency_key_reused`: the `Idempotency-Key` was already used with a different request.
- `429`: Rate limit exceeded for your key. Not charged. Wait `Retry-After` seconds.
- `500`: An unexpected failure on our side. The charge is refunded.
- `503`: The session-laws database is temporarily unavailable. The charge is refunded; retry.

## Changes

- **2026-11-07** `340c0d24d0b6`: 73 info
  - added the optional property `candidateCount` to the response with the `401` status
  - added the optional property `candidateCount` to the response with the `402` status
  - added the optional property `candidateCount` to the response with the `403` status
  - added the optional property `candidateCount` to the response with the `409` status
  - …69 more

[Operation history](https://skmtc.dev/vaquill/apis/vaquill-developer-api/changes/api/v1/us/session-laws/batch/post.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)
