> ## Documentation Index
> Fetch the complete documentation index at: https://vaquill.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a state session law's text

> The act's text exactly as printed, one page of about 30,000 characters at a
time, cut at a paragraph break where one is near. Follow `nextCursor` while
`hasMore` is true; `pageStart` / `pageEnd` / `totalChars` are character offsets
into the whole text, and concatenating the pages in order reproduces it.

**Cost**: 6 credits per page served. Read `estimatedBodyPages` on the law first
(`charCount` divided by about 30,000). A short act is one page; an omnibus act can
be many. Each page is charged on its own, so you can stop whenever you have enough.
`pagePrice` is what this page cost, `totalPages` the estimated pages in all, and
`estimatedRemainingCredits` the pages still to come times the price.

**Cost of reading a law.** Reading a whole law is `estimatedBodyPages` times the price
of one body page (6 credits). Both are on the record: `charCount` is its length
in characters and `estimatedBodyPages` is that divided by the page size (about
30,000 characters), rounded up, and null unless the text is served. Most acts
take a page or two. The longest we hold, Ohio's 2025 budget act (HB 96, 9,571,132
characters), takes about 320 pages, 1,920 credits to read in
full, so check `estimatedBodyPages` before you page through an omnibus act. Each body
response then carries `pagePrice` (what that page cost) and `estimatedRemainingCredits`
(the pages still to come times the price) so you can stop whenever you have enough.

**Where a page starts.** Follow `nextCursor` from the page before, or send `startChar`,
a character offset into the text (0-based, the scale of `pageStart` and `totalChars`),
to jump straight to a place you know without paging from the start. Send one or the
other, never both (a 422, uncharged). A `startChar` page costs and sizes the same as any
other, and returns a normal signed `nextCursor`. `startChar` has no version binding of
its own, so add `expectTextSha256` (the `textSha256` you read the text under, in
lowercase hex, 16 characters or more): if the text was re-collected since, the answer is
a 409 and nothing is charged. A `startChar` at or beyond the end is a 422, refunded.
There is no page-size parameter: a page is always about 30,000 characters, so
its price is fixed.

**Attribution.** Every outcome carries `citation`, `jurisdiction`, `session`,
`approvedDate` and `sourceUrl`, so a page is attributable on its own. `sourceUrl` is the
official copy on a government host and is present when the text is withheld or not held,
so a reader always has somewhere to go.

**Id only.** This route takes a `sessionLawId`, not a citation: resolve a citation
once with `GET /us/session-laws/{sessionLawId}` and use the id it returns.

**Not served, not charged.** When we do not serve the text (`textStatus` is not
`held`), the answer is a 200 with `available: false` and a `reason` (`not_held`,
`withheld`, `pending` or `empty_text`), `creditsConsumed: 0`, the
`withheldReason` for a withheld law, and the official `sourceUrl`. A federal id (`SAL_...`) is a 404
(`federal_session_law`); read federal session laws with
`GET /us/statutes/section/{actId}`. An unknown id is a 404; a stale cursor or a mismatched `expectTextSha256` is a 409
(start again without `cursor`); a malformed or expired cursor, `cursor` with `startChar`,
or a `startChar` past the end is a 422. None of these is
charged, and a failure on our side (500, 503) is refunded.

**Amendatory markup.** An amending act prints the language it deletes and inserts.
Where `amendatoryMarkup` is `preserved`, that markup is in `text` in the convention
`markupConvention` names: `wdiff` writes deleted language `[-like this-]` and
inserted language `{+like this+}`; `publisher_literal` keeps the publisher's own
markers as printed (Minnesota's `new text begin` and `deleted text begin`); `mixed`
has both. Where it is `lost`, the publisher printed markup our text does not keep,
so deleted words can read as law: check the source before quoting. Only the as
printed text is served; there is no clean "as enacted" view.

**Example**

```bash
curl "https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body" \
  -H "Authorization: Bearer $VAQUILL_API_KEY"

# jump to a character offset, pinned to the version of the text you read
curl "https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body?startChar=29987&expectTextSha256=02693d5b55d4709b" \
  -H "Authorization: Bearer $VAQUILL_API_KEY"
```

```javascript
const MY_BUDGET = 100; // the most you will spend to finish reading, in credits
let cursor;
let text = "";
do {
  const url = new URL("https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body");
  if (cursor) url.searchParams.set("cursor", cursor);
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.VAQUILL_API_KEY}` },
  });
  const page = await res.json();
  if (!page.available) break; // withheld or not held: page.sourceUrl is the official copy
  text += page.text;
  if (page.estimatedRemainingCredits > MY_BUDGET) break; // stop whenever you have enough
  cursor = page.nextCursor;
} while (cursor);
```

**Related endpoints**

- `GET /us/statutes/resolve` answers a citation that names a state session law
  rather than a code section with a `sessionLaw` block (`matched`, or `ambiguous`
  with every candidate), pointing here. It never changes `resolved` or `section`.
- `GET /us/statutes/coverage` lists, per jurisdiction under `sessionLaws`, which
  sessions we hold session laws for and whether each is `complete` or `partial`.
  Read it first: a law missing from a `partial` session is not evidence that it
  does not exist.
- Federal session laws (the Statutes at Large, `SAL_` ids) are not served here. Read
  them with `GET /us/statutes/section/{actId}`.

**Nulls.** Every field of a response is always present: one with no value is `null`
(or `[]` for a list). The examples on this page leave the nulls out for brevity. The
exceptions are blocks that exist only when they apply and are OMITTED otherwise, never
null: `publisher`, `provenance` and `session.coverageStatus` on a law, and `coverage` on a
list page that has rows.

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



## OpenAPI

````yaml https://api.vaquill.ai/external/openapi.json get /api/v1/us/session-laws/{session_law_id}/body
openapi: 3.1.0
info:
  title: Vaquill Developer API
  description: >-
    Public API for legal statutes and legislation.


    **Authentication**: Pass your API key as `Authorization: Bearer vq_key_...`
    (preferred) or in the `X-API-Key` header. The `api_key` query parameter also
    works where a header cannot be set, but a URL ends up in logs and browser
    history. Sending two different keys in one request is rejected with a 401.


    **Credits**: Each call costs API credits. See `GET
    /api/v1/api-credits/pricing` for the full pricing matrix.


    ## Jurisdictions


    | Jurisdiction | Coverage | `countryCode` |

    |---|---|---|

    | **United States** | USC and the Statutes at Large, the CFR and its annual
    editions, all 52 state and territory statutory codes (50 states plus DC and
    Puerto Rico), state administrative regulations, court rules, federal and
    state constitutions, federal agency guidance and adjudications, the Federal
    Register, the Sentencing Guidelines and US tax treaties. | `US` |


    See the full [Coverage page](https://www.vaquill.ai/docs/api-guide/coverage)
    for the jurisdiction-by-jurisdiction breakdown, or call
    `/us/statutes/coverage` for live counts. Coverage is per (jurisdiction,
    corpusType) pair, so treat that endpoint as the authoritative list rather
    than this summary.


    ## Endpoints


    - **US Statutes**: Search and retrieve any of the corpora above with full
    text, resolve a citation to its exact section, browse the statutory
    hierarchy, read a section as it stood on a past date, and follow its change
    history, cross-references and defined terms

    - **Board Watches**: Subscribe to a corpus source and get a webhook or email
    when it refreshes with real changes (free, API key required)

    - **Pricing**: Credit costs per endpoint (no auth required)


    ## Rate limits


    Limits are enforced per API key and scale with your plan. A `429` response
    includes a `Retry-After` header.


    | Plan | Per minute | Per hour | Per day |

    |---|---|---|---|

    | Vaquill API Pro | 60 | 1,000 | 2,000 |

    | Vaquill API Business | 150 | 2,500 | 10,000 |


    For full documentation, visit the [API
    Reference](https://www.vaquill.ai/docs/api-reference/).
  version: 1.0.0
  contact:
    name: Vaquill API Support
    url: https://www.vaquill.ai
    email: support@vaquill.ai
  license:
    name: Proprietary
    url: https://www.vaquill.ai/terms
  termsOfService: https://www.vaquill.ai/terms
servers:
  - url: https://api.vaquill.ai
    description: Production
security:
  - ApiKeyAuth: []
  - ApiKeyHeader: []
  - ApiKeyQuery: []
tags:
  - name: US Statutes
    description: >-
      Search and retrieve US primary law. Covers the United States Code and the
      Statutes at Large, the Code of Federal Regulations and its annual
      editions, state statutory codes and administrative regulations, federal
      and state constitutions, court rules, Federal Register rules and
      Presidential documents, federal and state agency guidance, agency
      adjudications, state Attorney General opinions, the Sentencing Guidelines
      and US tax treaties. Scope a search with the `corpusType` filter, and call
      `/us/statutes/coverage` for the live jurisdiction-by-corpusType list.


      - **Search**: Search across all USC, CFR, state, and regulatory sections

      - **Section**: Get metadata, citation, hierarchy, and source links for a
      specific section

      - **Body**: Get the full text of a section

      - **Enactments**: Which state session laws a publisher's own tables list
      against a section (supported jurisdictions only, never a complete history)
  - name: US Session Laws
    description: >-
      State session laws: the acts of each legislature as they were enacted,
      chapter by chapter, before they are folded into a code. A session law is
      what the governor signs. It carries the act's own text, including the
      language it strikes and inserts, its approval and effective dates, and,
      where the publisher prints one, the code sections it changes. That makes
      it the source for "which act changed this section, and when did it take
      effect".


      Every act has a permanent `sessionLawId` (for example
      `SSL_MN_2025R_G_Y2025_C1`, Minnesota Laws 2025, regular session, chapter
      1) whether or not we hold its text, and a citation or bill number such as
      `S.F.No. 1552` is accepted where an id goes. v1 serves STATE acts only.
      Federal session laws (the Statutes at Large, `SAL_` ids) are served by
      `/us/statutes/section`, and `/us/statutes/resolve` points a session-law
      citation here.


      **Start here**: check `/us/statutes/coverage` (free) for what we hold per
      state: each jurisdiction's `sessionLaws` block lists its sessions, which
      are complete or only partly collected, and the `series` and
      `instrumentTypes` that exist. Then **List** a session or a date range to
      get ids, **Get** one act for its record, then **Body** for its text. A law
      missing from a partly collected session is a free 404
      (`session_not_fully_collected`), not proof it does not exist.


      - **List**: everything enacted in a state's session, approved in a window,
      or taking effect on a date

      - **Get**: one act by id or by citation; dates (`effectiveDates` is always
      a list), sources and the code sections it affects

      - **Body**: the act's text as printed, paged by cursor, with amendatory
      markup preserved where the publisher printed it

      - **Batch**: up to 50 ids or citations in one call, the same record as
      Get, billed per law served, with every miss listed and its reason

      - **Changes**: a sync feed of the registry over an integer cursor
      (`sinceId`): what began to be served, was corrected, withdrawn or merged


      The reverse link, from a code section to the acts a publisher's own tables
      list against it, is `GET /us/statutes/section/{actId}/enactments`.
  - name: Board Watches
    description: >-
      Law-change alerts. Subscribe to a **board** (a tracked corpus source,
      identified by `corpusType` plus an optional `state`) and get a webhook or
      email whenever it refreshes with real changes, naming the exact sections
      that changed. Fetch old-vs-new text for any amended section via the change
      diff.


      Boards refresh on their own existing cadence; watching one does not change
      how often it refreshes. Every endpoint here is **free**: authenticated by
      API key and rate-limited, but not credit-metered.


      See the [Law Change Alerts
      guide](https://www.vaquill.ai/docs/api-guide/alerts) for the full
      walkthrough.
  - name: Pricing
    description: >-
      Credit pricing and conversion rates. No authentication required. 1 credit
      = $0.01 USD.
  - name: Credits
    description: >-
      Your own credit balance: what is spendable right now, where it came from,
      and what is about to expire.


      Free and never charged, so it is safe to poll for low-balance alerting or
      to pre-flight a batch job.
externalDocs:
  description: Full API Reference
  url: https://www.vaquill.ai/docs/api-reference/
paths:
  /api/v1/us/session-laws/{session_law_id}/body:
    get:
      tags:
        - US Session Laws
      summary: Get a state session law's text
      description: >-
        The act's text exactly as printed, one page of about 30,000 characters
        at a

        time, cut at a paragraph break where one is near. Follow `nextCursor`
        while

        `hasMore` is true; `pageStart` / `pageEnd` / `totalChars` are character
        offsets

        into the whole text, and concatenating the pages in order reproduces it.


        **Cost**: 6 credits per page served. Read `estimatedBodyPages` on the
        law first

        (`charCount` divided by about 30,000). A short act is one page; an
        omnibus act can

        be many. Each page is charged on its own, so you can stop whenever you
        have enough.

        `pagePrice` is what this page cost, `totalPages` the estimated pages in
        all, and

        `estimatedRemainingCredits` the pages still to come times the price.


        **Cost of reading a law.** Reading a whole law is `estimatedBodyPages`
        times the price

        of one body page (6 credits). Both are on the record: `charCount` is its
        length

        in characters and `estimatedBodyPages` is that divided by the page size
        (about

        30,000 characters), rounded up, and null unless the text is served. Most
        acts

        take a page or two. The longest we hold, Ohio's 2025 budget act (HB 96,
        9,571,132

        characters), takes about 320 pages, 1,920 credits to read in

        full, so check `estimatedBodyPages` before you page through an omnibus
        act. Each body

        response then carries `pagePrice` (what that page cost) and
        `estimatedRemainingCredits`

        (the pages still to come times the price) so you can stop whenever you
        have enough.


        **Where a page starts.** Follow `nextCursor` from the page before, or
        send `startChar`,

        a character offset into the text (0-based, the scale of `pageStart` and
        `totalChars`),

        to jump straight to a place you know without paging from the start. Send
        one or the

        other, never both (a 422, uncharged). A `startChar` page costs and sizes
        the same as any

        other, and returns a normal signed `nextCursor`. `startChar` has no
        version binding of

        its own, so add `expectTextSha256` (the `textSha256` you read the text
        under, in

        lowercase hex, 16 characters or more): if the text was re-collected
        since, the answer is

        a 409 and nothing is charged. A `startChar` at or beyond the end is a
        422, refunded.

        There is no page-size parameter: a page is always about 30,000
        characters, so

        its price is fixed.


        **Attribution.** Every outcome carries `citation`, `jurisdiction`,
        `session`,

        `approvedDate` and `sourceUrl`, so a page is attributable on its own.
        `sourceUrl` is the

        official copy on a government host and is present when the text is
        withheld or not held,

        so a reader always has somewhere to go.


        **Id only.** This route takes a `sessionLawId`, not a citation: resolve
        a citation

        once with `GET /us/session-laws/{sessionLawId}` and use the id it
        returns.


        **Not served, not charged.** When we do not serve the text (`textStatus`
        is not

        `held`), the answer is a 200 with `available: false` and a `reason`
        (`not_held`,

        `withheld`, `pending` or `empty_text`), `creditsConsumed: 0`, the

        `withheldReason` for a withheld law, and the official `sourceUrl`. A
        federal id (`SAL_...`) is a 404

        (`federal_session_law`); read federal session laws with

        `GET /us/statutes/section/{actId}`. An unknown id is a 404; a stale
        cursor or a mismatched `expectTextSha256` is a 409

        (start again without `cursor`); a malformed or expired cursor, `cursor`
        with `startChar`,

        or a `startChar` past the end is a 422. None of these is

        charged, and a failure on our side (500, 503) is refunded.


        **Amendatory markup.** An amending act prints the language it deletes
        and inserts.

        Where `amendatoryMarkup` is `preserved`, that markup is in `text` in the
        convention

        `markupConvention` names: `wdiff` writes deleted language `[-like
        this-]` and

        inserted language `{+like this+}`; `publisher_literal` keeps the
        publisher's own

        markers as printed (Minnesota's `new text begin` and `deleted text
        begin`); `mixed`

        has both. Where it is `lost`, the publisher printed markup our text does
        not keep,

        so deleted words can read as law: check the source before quoting. Only
        the as

        printed text is served; there is no clean "as enacted" view.


        **Example**


        ```bash

        curl
        "https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body"
        \
          -H "Authorization: Bearer $VAQUILL_API_KEY"

        # jump to a character offset, pinned to the version of the text you read

        curl
        "https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body?startChar=29987&expectTextSha256=02693d5b55d4709b"
        \
          -H "Authorization: Bearer $VAQUILL_API_KEY"
        ```


        ```javascript

        const MY_BUDGET = 100; // the most you will spend to finish reading, in
        credits

        let cursor;

        let text = "";

        do {
          const url = new URL("https://api.vaquill.ai/api/v1/us/session-laws/SSL_MN_2025S1_G_Y2025_C1/body");
          if (cursor) url.searchParams.set("cursor", cursor);
          const res = await fetch(url, {
            headers: { Authorization: `Bearer ${process.env.VAQUILL_API_KEY}` },
          });
          const page = await res.json();
          if (!page.available) break; // withheld or not held: page.sourceUrl is the official copy
          text += page.text;
          if (page.estimatedRemainingCredits > MY_BUDGET) break; // stop whenever you have enough
          cursor = page.nextCursor;
        } while (cursor);

        ```


        **Related endpoints**


        - `GET /us/statutes/resolve` answers a citation that names a state
        session law
          rather than a code section with a `sessionLaw` block (`matched`, or `ambiguous`
          with every candidate), pointing here. It never changes `resolved` or `section`.
        - `GET /us/statutes/coverage` lists, per jurisdiction under
        `sessionLaws`, which
          sessions we hold session laws for and whether each is `complete` or `partial`.
          Read it first: a law missing from a `partial` session is not evidence that it
          does not exist.
        - Federal session laws (the Statutes at Large, `SAL_` ids) are not
        served here. Read
          them with `GET /us/statutes/section/{actId}`.

        **Nulls.** Every field of a response is always present: one with no
        value is `null`

        (or `[]` for a list). The examples on this page leave the nulls out for
        brevity. The

        exceptions are blocks that exist only when they apply and are OMITTED
        otherwise, never

        null: `publisher`, `provenance` and `session.coverageStatus` on a law,
        and `coverage` on a

        list page that has rows.


        **Rate limits.** Calls count against your key's per-minute budget like
        every Data

        API route; a 429 carries `Retry-After`.
      operationId: get_session_law_body_api_v1_us_session_laws__session_law_id__body_get
      parameters:
        - name: session_law_id
          in: path
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 300
            description: >-
              A STATE session law's id, for example `SSL_MN_2025S1_G_Y2025_C1`,
              from a `/us/session-laws/list` result.


              A citation also works here on `GET
              /us/session-laws/{sessionLawId}`, and `resolvedFrom` says what
              your input matched. Name the state in the citation: `Minn. Laws
              2025, ch. 1`, `2025 Minn. Laws ch. 1`, `Ch. 1, Laws of Minnesota
              2025`, `Ch. 2025-12, Laws of Fla.`, `2025 Wash. Sess. Laws ch.
              12`, `La. Acts 2025, No. 12`, `Pa. Act 12 of 2025`, `Minn. S.F.
              1552 (2025)`, `MN: Laws 2025, ch. 1`. A form only one state uses
              needs no state: `P.A. 104-0001` (Illinois), `Pub. Act No. 26-151`
              (Connecticut), `S.L. 2025-12` (North Carolina), `Stats. 2025, ch.
              12` (California), `D.C. Law 25-713`. The publisher's printed form
              (`CHAPTER 2025-12`, `S.F.No. 1552`) and the `citation` we print on
              every law also work. A form several states share (`Laws 2025, ch.
              1`, `HB 123`, `Act 12 of 2025`) is a 404 with `reason:
              needs_jurisdiction`, the states it exists in and one candidate per
              state: we never guess the state. A citation naming several laws of
              one state (Minnesota 2025 has two Chapter 1s) is a 404 listing all
              of them, `candidateCount` and `truncated` saying whether the list
              is complete, and `defaultSessionLawId` the regular session's law
              where there is exactly one conventional reading. An id or citation
              that matches nothing in a session we have only partly collected is
              a 404 with `reason: session_not_fully_collected` and that
              session's coverage: the law may exist and not be held yet, so it
              is never charged, the resolve price included. A citation costs the
              route's price PLUS the `/us/statutes/resolve` price (2 credits),
              the second charged whether or not it resolves. URL-encode the
              citation; one containing `/` cannot travel in a path segment.


              Federal session laws (`SAL_...`, `Pub. L. 118-5`, the Statutes at
              Large) are served by `/us/statutes/section`, not here, and code
              citations (`26 U.S.C. § 1`) by `/us/statutes/resolve`.
            examples:
              - SSL_MN_2025S1_G_Y2025_C1
            title: Session Law Id
          description: >-
            A STATE session law's id, for example `SSL_MN_2025S1_G_Y2025_C1`,
            from a `/us/session-laws/list` result.


            A citation also works here on `GET /us/session-laws/{sessionLawId}`,
            and `resolvedFrom` says what your input matched. Name the state in
            the citation: `Minn. Laws 2025, ch. 1`, `2025 Minn. Laws ch. 1`,
            `Ch. 1, Laws of Minnesota 2025`, `Ch. 2025-12, Laws of Fla.`, `2025
            Wash. Sess. Laws ch. 12`, `La. Acts 2025, No. 12`, `Pa. Act 12 of
            2025`, `Minn. S.F. 1552 (2025)`, `MN: Laws 2025, ch. 1`. A form only
            one state uses needs no state: `P.A. 104-0001` (Illinois), `Pub. Act
            No. 26-151` (Connecticut), `S.L. 2025-12` (North Carolina), `Stats.
            2025, ch. 12` (California), `D.C. Law 25-713`. The publisher's
            printed form (`CHAPTER 2025-12`, `S.F.No. 1552`) and the `citation`
            we print on every law also work. A form several states share (`Laws
            2025, ch. 1`, `HB 123`, `Act 12 of 2025`) is a 404 with `reason:
            needs_jurisdiction`, the states it exists in and one candidate per
            state: we never guess the state. A citation naming several laws of
            one state (Minnesota 2025 has two Chapter 1s) is a 404 listing all
            of them, `candidateCount` and `truncated` saying whether the list is
            complete, and `defaultSessionLawId` the regular session's law where
            there is exactly one conventional reading. An id or citation that
            matches nothing in a session we have only partly collected is a 404
            with `reason: session_not_fully_collected` and that session's
            coverage: the law may exist and not be held yet, so it is never
            charged, the resolve price included. A citation costs the route's
            price PLUS the `/us/statutes/resolve` price (2 credits), the second
            charged whether or not it resolves. URL-encode the citation; one
            containing `/` cannot travel in a path segment.


            Federal session laws (`SAL_...`, `Pub. L. 118-5`, the Statutes at
            Large) are served by `/us/statutes/section`, not here, and code
            citations (`26 U.S.C. § 1`) by `/us/statutes/resolve`.
        - name: cursor
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                maxLength: 600
              - type: 'null'
            description: >-
              Where to resume: the previous page's `nextCursor`, unchanged. Omit
              for the first page. It is opaque, signed and tied to the exact
              text it was cut from: a value we did not issue (`reason:
              invalid_cursor`), from an older cursor format (`cursor_expired`)
              or past the end of the text (`cursor_past_end`) is a 422, and one
              from before the text was re-collected is a 409 (start again
              without it). None is charged. Send either `cursor` or `startChar`,
              never both (a 422, never charged).
            examples:
              - >-
                eyJ2IjoyLCJvIjoyOTk4NywiaCI6IjAyNjkzZDViNTVkNDcwOWIifQ.stWHVSgGqJPIElcTLfAGHA
            title: Cursor
          description: >-
            Where to resume: the previous page's `nextCursor`, unchanged. Omit
            for the first page. It is opaque, signed and tied to the exact text
            it was cut from: a value we did not issue (`reason:
            invalid_cursor`), from an older cursor format (`cursor_expired`) or
            past the end of the text (`cursor_past_end`) is a 422, and one from
            before the text was re-collected is a 409 (start again without it).
            None is charged. Send either `cursor` or `startChar`, never both (a
            422, never charged).
        - name: startChar
          in: query
          required: false
          schema:
            anyOf:
              - type: integer
                maximum: 100000000
                minimum: 0
              - type: 'null'
            description: >-
              Start the page at this character offset into the text (0-based,
              the same scale as `pageStart` and `totalChars`): an alternative to
              `cursor` for jumping to a place you already know, such as the
              character where a section begins, without paging from the start.
              The page that comes back is the same size and price as any other,
              its `nextCursor` is a normal signed cursor you can follow, and a
              page is still cut at a paragraph break near its end. Send either
              `startChar` or `cursor`, never both (a 422, never charged). 0 to
              100,000,000; a value at or beyond the end of the text is a 422 and
              is refunded. There is no page-size parameter: the price per page
              is fixed.
            examples:
              - 29987
            title: Startchar
          description: >-
            Start the page at this character offset into the text (0-based, the
            same scale as `pageStart` and `totalChars`): an alternative to
            `cursor` for jumping to a place you already know, such as the
            character where a section begins, without paging from the start. The
            page that comes back is the same size and price as any other, its
            `nextCursor` is a normal signed cursor you can follow, and a page is
            still cut at a paragraph break near its end. Send either `startChar`
            or `cursor`, never both (a 422, never charged). 0 to 100,000,000; a
            value at or beyond the end of the text is a 422 and is refunded.
            There is no page-size parameter: the price per page is fixed.
        - name: expectTextSha256
          in: query
          required: false
          schema:
            anyOf:
              - type: string
                pattern: ^[0-9a-f]{16,64}$
              - type: 'null'
            description: >-
              The `textSha256` you read the text under, in lowercase hex (the
              whole 64 characters, or any prefix of 16 or more). When this law's
              text no longer has that hash (it was re-collected), the answer is
              a 409 and nothing is charged, exactly as for a `cursor` cut from
              an earlier version: use it with `startChar`, which otherwise has
              no version binding of its own. Anything that is not 16 to 64
              lowercase hex characters is a 422.
            examples:
              - 02693d5b55d4709bdd36fdccee4a9737d2655a3988a90daeb6b7c486ce50260b
            title: Expecttextsha256
          description: >-
            The `textSha256` you read the text under, in lowercase hex (the
            whole 64 characters, or any prefix of 16 or more). When this law's
            text no longer has that hash (it was re-collected), the answer is a
            409 and nothing is charged, exactly as for a `cursor` cut from an
            earlier version: use it with `startChar`, which otherwise has no
            version binding of its own. Anything that is not 16 to 64 lowercase
            hex characters is a 422.
      responses:
        '200':
          description: >-
            One page of the act's text, or `available: false` (not charged) when
            we do not serve it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SessionLawBodyResponse'
              examples:
                firstPage:
                  summary: Page 1 of a long act (text abbreviated here)
                  value:
                    sessionLawId: SSL_MN_2025S1_G_Y2025_C1
                    citation: CHAPTER 1--S.F.No. 3
                    jurisdiction: mn
                    session:
                      code: 2025S1
                      label: 2025 1st Special Session
                      type: special
                      year: 2025
                    approvedDate: '2025-06-14'
                    approvedDateDerived: false
                    sourceUrl: >-
                      https://www.revisor.mn.gov/laws/2025/1/Session+Law/Chapter/1/
                    available: true
                    textStatus: held
                    text: >-
                      CHAPTER 1--S.F.No. 3


                      An act


                      relating to state government; appropriating money for
                      environment and natural resources; appropriating money
                      from environment and natural resources trust fund;
                      modifying prior appropriations; modifying fees and
                      surcharges; ...
                    pageStart: 0
                    pageEnd: 29987
                    totalChars: 310454
                    totalPages: 11
                    pagePrice: 6
                    estimatedRemainingCredits: 60
                    textSha256: >-
                      02693d5b55d4709bdd36fdccee4a9737d2655a3988a90daeb6b7c486ce50260b
                    amendatoryMarkup: preserved
                    markupConvention: publisher_literal
                    nextCursor: >-
                      eyJ2IjoyLCJvIjoyOTk4NywiaCI6IjAyNjkzZDViNTVkNDcwOWIifQ.stWHVSgGqJPIElcTLfAGHA
                    hasMore: true
                    processingTimeMs: 612.3
                    creditsConsumed: 6
                startChar:
                  summary: >-
                    startChar=29987: the page that begins where page 1 ended, no
                    cursor needed
                  value:
                    sessionLawId: SSL_MN_2025S1_G_Y2025_C1
                    citation: CHAPTER 1--S.F.No. 3
                    jurisdiction: mn
                    session:
                      code: 2025S1
                      label: 2025 1st Special Session
                      type: special
                      year: 2025
                    approvedDate: '2025-06-14'
                    approvedDateDerived: false
                    sourceUrl: >-
                      https://www.revisor.mn.gov/laws/2025/1/Session+Law/Chapter/1/
                    available: true
                    textStatus: held
                    text: >-
                      ...(continues at character 29987, cut at the paragraph
                      break before it) ...
                    pageStart: 29987
                    pageEnd: 59974
                    totalChars: 310454
                    totalPages: 11
                    pagePrice: 6
                    estimatedRemainingCredits: 54
                    textSha256: >-
                      02693d5b55d4709bdd36fdccee4a9737d2655a3988a90daeb6b7c486ce50260b
                    amendatoryMarkup: preserved
                    markupConvention: publisher_literal
                    nextCursor: >-
                      eyJ2IjoyLCJvIjo1OTk3NCwiaCI6IjAyNjkzZDViNTVkNDcwOWIifQ.9KqnMFXT9SmUwN9e7TzHKA
                    hasMore: true
                    processingTimeMs: 612.3
                    creditsConsumed: 6
                onePageAct:
                  summary: >-
                    A short act is one page: the last page has no nextCursor and
                    nothing remains
                  value:
                    sessionLawId: SSL_MN_2025R_G_Y2025_C1
                    citation: CHAPTER 1--S.F.No. 1552
                    jurisdiction: mn
                    session:
                      code: 2025R
                      label: 2025 Regular Session
                      type: regular
                      year: 2025
                    approvedDate: '2025-03-17'
                    approvedDateDerived: false
                    sourceUrl: >-
                      https://www.revisor.mn.gov/laws/2025/0/Session+Law/Chapter/1/
                    available: true
                    textStatus: held
                    text: >-
                      CHAPTER 1--S.F.No. 1552


                      An act


                      relating to agriculture; modifying financial reporting
                      requirements for grain buyers; amending Minnesota Statutes
                      2024, section 223.17, subdivision 6. ...
                    pageStart: 0
                    pageEnd: 5470
                    totalChars: 5470
                    totalPages: 1
                    pagePrice: 6
                    estimatedRemainingCredits: 0
                    textSha256: >-
                      55c7a8d08647e41f87e23fc2016881a6583911a1d5cfa8687403442e9096451b
                    amendatoryMarkup: preserved
                    markupConvention: publisher_literal
                    hasMore: false
                    processingTimeMs: 318.9
                    creditsConsumed: 6
                withheld:
                  summary: 'A withheld law: available false, nothing charged'
                  value:
                    sessionLawId: SSL_LA_2025R_G_C2
                    citation: ACT No. 2
                    jurisdiction: la
                    session:
                      code: 2025R
                      label: 2025 Regular Session
                      type: regular
                      year: 2025
                    approvedDate: '2025-06-20'
                    approvedDateDerived: false
                    sourceUrl: https://www.legis.la.gov/legis/ViewDocument.aspx?d=1426048
                    available: false
                    reason: withheld
                    textStatus: withheld
                    withheldReason: >-
                      LA: struck (deleted) law is merged into the text as if
                      current while the record declares the markup preserved or
                      absent (audit 2026-10-03). Awaiting a re-run with strike
                      and underline recovery.
                    pagePrice: 0
                    amendatoryMarkup: absent
                    hasMore: false
                    processingTimeMs: 41.7
                    creditsConsumed: 0
        '401':
          description: Missing, invalid or revoked API key. Not charged.
          content:
            application/json:
              example:
                detail: Invalid or expired API key
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '402':
          description: >-
            Insufficient credits for this call. Nothing was done and nothing was
            charged. Read your balance, free, at `GET /credits/balance`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiDetailError'
              example:
                detail: Insufficient credits
        '403':
          description: The API key lacks the `research:read` scope. Not charged.
          content:
            application/json:
              example:
                detail: Insufficient permissions for this operation
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '404':
          description: >-
            Unknown id, a federal act, or an endpoint name where the id goes.
            `reason` says which. Never charged.
          content:
            application/json:
              examples:
                not_in_registry:
                  summary: No law carries this id
                  value:
                    detail: >-
                      Session law not found. No law in the registry carries this
                      id. Take ids from a /us/session-laws/list result. This
                      route takes ids only, not citations: GET
                      /us/session-laws/{sessionLawId} accepts a citation and
                      returns the id to send here.
                    sessionLawId: SSL_MN_1801R_G_Y1801_C9999
                    reason: not_in_registry
                    didYouMean: []
                wrong_case:
                  summary: The id exists in another letter case (never served for you)
                  value:
                    detail: >-
                      Session law not found. Ids are case-sensitive and this one
                      exists in a different case; see didYouMean.
                    sessionLawId: ssl_mn_2025r_g_y2025_c1
                    reason: wrong_case
                    didYouMean:
                      - SSL_MN_2025R_G_Y2025_C1
                federal_session_law:
                  summary: >-
                    A federal act: served by /us/statutes/section, refused
                    before any charge
                  value:
                    detail: >-
                      Session law not found. This endpoint covers STATE session
                      laws; federal session laws (the Statutes at Large) are
                      served by GET /us/statutes/section/{actId}. A federal id
                      (`SAL_...`) is not charged; a federal citation typed in
                      its place keeps the /us/statutes/resolve price, like any
                      unresolved citation.
                    sessionLawId: SAL_PL118-5
                    reason: federal_session_law
                    didYouMean: []
                missing_session_law_id:
                  summary: >-
                    An endpoint name where the id goes, refused before any
                    charge
                  value:
                    detail: >-
                      Session law not found. The URL has no session-law id in
                      it: the segment where the id goes names an endpoint, for
                      example /us/session-laws/{sessionLawId}/body. Nothing was
                      charged.
                    sessionLawId: body
                    reason: missing_session_law_id
                    didYouMean: []
                session_not_fully_collected:
                  summary: >-
                    Nothing matched, and the session is only partly collected:
                    the law may exist (nothing is charged, the resolve price
                    included)
                  value:
                    detail: >-
                      Session law not found. Nothing matched, and the session
                      this points into is only partly collected, so the law may
                      exist and not be held yet. `sessionCoverage` says how much
                      of the session we hold. Nothing was charged: a miss in a
                      partly collected session is never billed.
                    sessionLawId: SSL_DE_2025R_G_C3
                    reason: session_not_fully_collected
                    didYouMean: []
                    sessionCoverage:
                      code: 2025R
                      label: 153rd General Assembly
                      type: regular
                      year: 2025
                      status: partial
                      servedCount: 43
                      withheldCount: 0
                      notHeldCount: 0
                      registryCount: 43
                      collectedCount: 43
                      denominator:
                        kind: complete_listing
                        value: 296
                        derivation: >-
                          The publisher's complete listing of this session names
                          296 measures. We hold 43 of them; the rest are not yet
                          collected.
                      openGaps: 253
              schema:
                $ref: '#/components/schemas/SessionLawNotFoundError'
        '409':
          description: >-
            The `cursor` was cut from an earlier version of this law's text, or
            the `expectTextSha256` you sent is not its hash: the text has since
            been re-collected. Not charged. Start again without `cursor`.
          content:
            application/json:
              examples:
                staleCursor:
                  summary: A `cursor` from before the text was re-collected
                  value:
                    detail: >-
                      This cursor belongs to an earlier version of the text.
                      Start again without `cursor`.
                staleHash:
                  summary: An `expectTextSha256` that is no longer the text's hash
                  value:
                    detail: >-
                      The text of this law no longer matches `expectTextSha256`
                      (it was re-collected). Read `textSha256` from the law and
                      start again.
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '422':
          description: >-
            A parameter failed validation: a `cursor` we did not issue, `cursor`
            sent with `startChar`, or a malformed `startChar` or
            `expectTextSha256`. Never charged. `errors[].loc` names the
            parameter exactly as you send it.
          content:
            application/json:
              examples:
                badCursor:
                  summary: A `cursor` this API did not issue
                  value:
                    detail: '`cursor` is not one this API issued.'
                    reason: invalid_cursor
                cursorExpired:
                  summary: A `cursor` from before the cursor format changed
                  value:
                    detail: >-
                      `cursor` is from an earlier version of this API and has
                      expired. Restart without `cursor`.
                    reason: cursor_expired
                cursorPastEnd:
                  summary: >-
                    A `cursor` at or beyond the end of the text (never issued by
                    this API)
                  value:
                    detail: >-
                      `cursor` points past the end of this law's text. A final
                      page has no `nextCursor`: restart without `cursor`.
                    reason: cursor_past_end
                cursorAndStartChar:
                  summary: >-
                    `cursor` and `startChar` together: a cursor already says
                    where the page starts
                  value:
                    detail: >-
                      Send either `cursor` or `startChar`, not both: a cursor
                      already says where the page starts.
                startCharPastEnd:
                  summary: '`startChar=400000` on a text of 310454 characters (refunded)'
                  value:
                    detail: >-
                      `startChar` (400000) is at or beyond the end of this law's
                      text, which is 310454 characters long. Nothing was
                      charged.
                startCharNegative:
                  summary: '`startChar=-1`'
                  value:
                    detail: Invalid request parameters
                    errors:
                      - loc:
                          - query
                          - startChar
                        msg: Input should be greater than or equal to 0
                        type: greater_than_equal
                badExpectTextSha256:
                  summary: '`expectTextSha256=abc`: 16 to 64 lowercase hex characters'
                  value:
                    detail: Invalid request parameters
                    errors:
                      - loc:
                          - query
                          - expectTextSha256
                        msg: String should match pattern '^[0-9a-f]{16,64}$'
                        type: string_pattern_mismatch
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '429':
          description: >-
            Rate limit exceeded for your key. Not charged. Wait `Retry-After`
            seconds.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
                examples:
                  - 12
            X-RateLimit-Limit:
              description: Requests per minute your key is allowed.
              schema:
                type: integer
                examples:
                  - 60
            X-RateLimit-Remaining:
              description: Requests left in the current minute. 0 on a 429.
              schema:
                type: integer
                examples:
                  - 0
            X-RateLimit-Reset:
              description: Unix time at which the minute window resets.
              schema:
                type: integer
                examples:
                  - 1791194460
          content:
            application/json:
              example:
                detail: Rate limit exceeded. Try again in 12 seconds.
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '500':
          description: An unexpected failure on our side. The charge is refunded.
          content:
            application/json:
              example:
                detail: Internal server error
              schema:
                $ref: '#/components/schemas/ApiDetailError'
        '503':
          description: >-
            The session-laws database is temporarily unavailable. The charge is
            refunded; retry.
          content:
            application/json:
              example:
                detail: >-
                  The US session-laws database is temporarily unavailable.
                  Please retry.
              schema:
                $ref: '#/components/schemas/ApiDetailError'
components:
  schemas:
    SessionLawBodyResponse:
      properties:
        processingTimeMs:
          type: number
          title: Processingtimems
          description: >-
            Server-side time for this request in milliseconds, excluding network
            transit. Not billed on.
          default: 0
          examples:
            - 747.5
        creditsConsumed:
          type: integer
          title: Creditsconsumed
          description: >-
            Credits actually charged for this call, never the list price. It
            includes the `/us/statutes/resolve` fee when a citation was sent
            where an id goes. 0 when the call was not charged or was refunded (a
            body that answers `available: false`).
          default: 0
          examples:
            - 2
        sessionLawId:
          type: string
          title: Sessionlawid
          description: The law this page belongs to.
          examples:
            - SSL_MN_2025S1_G_Y2025_C1
        citation:
          type: string
          title: Citation
          description: >-
            The act's citation as its publisher prints it, the same as
            `citation` on `GET /us/session-laws/{sessionLawId}`. Carried here so
            a page is attributable on its own, with no second call.
          examples:
            - CHAPTER 1--S.F.No. 3
        jurisdiction:
          type: string
          title: Jurisdiction
          description: Lowercase two-letter code of the state, `dc` or `pr`.
          examples:
            - mn
        session:
          $ref: '#/components/schemas/SessionLawSession'
          description: The legislative session the law was enacted in.
        approvedDate:
          anyOf:
            - type: string
              format: date
            - type: 'null'
          title: Approveddate
          description: >-
            Date the governor approved the act, ISO 8601, as on `GET
            /us/session-laws/{sessionLawId}`: never an effective date. Null when
            none is held. See `approvedDateDerived`.
          examples:
            - '2025-06-14'
        approvedDateDerived:
          type: boolean
          title: Approveddatederived
          description: >-
            True only when `approvedDate` was filled from the publisher's dated
            signature label rather than held as the approval date. See the same
            field on `GET /us/session-laws/{sessionLawId}`.
          default: false
          examples:
            - false
        sourceUrl:
          anyOf:
            - type: string
            - type: 'null'
          title: Sourceurl
          description: >-
            The official page or file this text was collected from, on a
            government publisher's host. Present on EVERY outcome, a withheld or
            not-held law included, so a reader is never at a dead end: where we
            do not serve the text, this is where to read it. Null only when we
            hold no government text source for the law.
          examples:
            - https://www.revisor.mn.gov/laws/2025/1/Session+Law/Chapter/1/
        available:
          type: boolean
          title: Available
          description: >-
            False when we do not serve this law's text; `reason` says why. A
            page with `available: false` is not charged.
          examples:
            - true
        reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Reason
          description: >-
            Why `available` is false: `not_held`, `withheld`, `pending` or
            `empty_text`. Null when the text is served.
          examples:
            - withheld
            - null
        textStatus:
          type: string
          enum:
            - held
            - withheld
            - not_held
            - pending
          title: Textstatus
          description: >-
            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.
          examples:
            - held
        withheldReason:
          anyOf:
            - type: string
            - type: 'null'
          title: Withheldreason
          description: >-
            Present only when `textStatus` is `withheld`: what is wrong with the
            text we hold. A plain sentence to show, not an enum to branch on.
          examples:
            - >-
              LA: struck (deleted) law is merged into the text as if current
              while the record declares the markup preserved or absent (audit
              2026-10-03). Awaiting a re-run with strike and underline recovery.
            - null
        text:
          anyOf:
            - type: string
            - type: 'null'
          title: Text
          description: >-
            This page of the act's text, exactly as printed, in reading order.
            Concatenating every page's `text` in order reproduces the whole
            text. Where `amendatoryMarkup` is `preserved`, struck and inserted
            language is in the text in the convention `markupConvention` names.
            Null when `available` is false.
          examples:
            - |-
              CHAPTER 1--S.F.No. 1552

              An act

              relating to agriculture; ...
        pageStart:
          anyOf:
            - type: integer
            - type: 'null'
          title: Pagestart
          description: >-
            Character offset in the full text where this page starts (0-based).
            Pages are contiguous: the next page's `pageStart` equals this page's
            `pageEnd`.
          examples:
            - 0
        pageEnd:
          anyOf:
            - type: integer
            - type: 'null'
          title: Pageend
          description: >-
            Character offset just past this page. A page is about 30,000
            characters, cut back to a paragraph break where one is near, so the
            length varies.
          examples:
            - 29987
        totalChars:
          anyOf:
            - type: integer
            - type: 'null'
          title: Totalchars
          description: >-
            Length of the whole text in characters. This page is the last when
            `pageEnd` equals it.
          examples:
            - 310454
        totalPages:
          anyOf:
            - type: integer
            - type: 'null'
          title: Totalpages
          description: >-
            Estimated pages in the whole text: `totalChars` divided by the page
            size, rounded up. Pages are cut back to a paragraph break, so a long
            act can run a few percent over. Null when no text is served.
          examples:
            - 11
        pagePrice:
          type: integer
          title: Pageprice
          description: >-
            Credits charged for the page in this response, the same as
            `creditsConsumed` on this route: the price of one page when a page
            was served, 0 when none was (`available` is false). Each further
            page costs the same.
          default: 0
          examples:
            - 6
        estimatedRemainingCredits:
          anyOf:
            - type: integer
            - type: 'null'
          title: Estimatedremainingcredits
          description: >-
            Estimated credits to read the rest of the text from `pageEnd`: the
            pages still to come (`totalChars` less `pageEnd`, over the page
            size, rounded up) times the price of a page. 0 on the last page.
            Null when no text is served. An estimate: a page cut back to a
            paragraph break can add a page on a long act. Reading a whole law
            costs `estimatedBodyPages` times the price of one body page (6
            credits per page on `GET /us/session-laws/{sessionLawId}/body`).
            Ohio's 2025 budget act (HB 96) is 9,571,132 characters, about 320
            pages or 1,920 credits to read in full; most acts are a page or two.
          examples:
            - 60
        textSha256:
          anyOf:
            - type: string
            - type: 'null'
          title: Textsha256
          description: >-
            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.
          examples:
            - 02693d5b55d4709bdd36fdccee4a9737d2655a3988a90daeb6b7c486ce50260b
        amendatoryMarkup:
          anyOf:
            - type: string
            - type: 'null'
          title: Amendatorymarkup
          description: >-
            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.
          examples:
            - preserved
        markupConvention:
          anyOf:
            - type: string
            - type: 'null'
          title: Markupconvention
          description: >-
            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.
          examples:
            - publisher_literal
            - null
        nextCursor:
          anyOf:
            - type: string
            - type: 'null'
          title: Nextcursor
          description: >-
            Opaque cursor for the next page: send it as `cursor` on the same
            path. Null on the last page. It is tied to this exact text, so a
            cursor from before the text was re-collected is a 409.
          examples:
            - eyJ2IjoxLCJvIjoyOTk4NywiaCI6IjAyNjkzZDViNTVkNDcwOWIifQ
        hasMore:
          type: boolean
          title: Hasmore
          description: >-
            True when more pages follow; fetch them with `nextCursor`. Each page
            is charged.
          default: false
          examples:
            - true
      type: object
      required:
        - sessionLawId
        - citation
        - jurisdiction
        - session
        - available
        - textStatus
      title: SessionLawBodyResponse
      description: Response for `GET /us/session-laws/{sessionLawId}/body`.
    ApiDetailError:
      properties:
        detail:
          type: string
          title: Detail
          description: >-
            Human-readable reason, safe to surface to an end user. Branch on the
            HTTP status rather than on this string: the wording is not part of
            the contract and may be reworded, but 401 (bad key), 402 (out of
            credits), 403 (missing scope), 404 (no such resource) and 429 (rate
            limited) are stable.
          examples:
            - Insufficient API credits.
        errors:
          anyOf:
            - items:
                $ref: '#/components/schemas/ApiFieldError'
              type: array
            - type: 'null'
          title: Errors
          description: 'Present on 422 only: every field that failed validation.'
      type: object
      required:
        - detail
      title: ApiDetailError
      description: >-
        Error envelope the API actually returns.


        Every error (400/401/402/403/404/405/422/429/5xx) carries a `detail`

        string, e.g. `{"detail": "Insufficient API credits."}`, on every mount
        of

        the API. A 422 adds `errors`, one entry per rejected field. Some 404s
        add

        endpoint-specific diagnosis beside `detail` (the statutes section routes

        add `actId`, `reason` and `didYouMean`); treat unknown keys as optional.
    SessionLawNotFoundError:
      properties:
        detail:
          type: string
          title: Detail
          description: >-
            Human-readable reason, safe to show a user. Branch on `reason`, not
            on this string: the wording can change.
          examples:
            - >-
              Session law not found. No law in the registry carries this id.
              Take ids from a /us/session-laws/list result, or send the citation
              in its place.
        sessionLawId:
          type: string
          title: Sessionlawid
          description: The identifier exactly as you sent it.
          examples:
            - SSL_MN_1801R_G_Y1801_C9999
        reason:
          type: string
          enum:
            - not_in_registry
            - wrong_case
            - unresolved_citation
            - ambiguous_citation
            - federal_session_law
            - missing_session_law_id
            - needs_jurisdiction
            - session_not_fully_collected
          title: Reason
          description: >-
            `not_in_registry`: no law carries this id. `wrong_case`: it exists
            in another letter case, see `didYouMean`. `unresolved_citation`: you
            sent a citation and no law carries it. `ambiguous_citation`: the
            citation names several laws, all in `didYouMean`, none chosen for
            you; `defaultSessionLawId` is the publisher's conventional reading
            when one is recorded. `federal_session_law`: federal acts are served
            by /us/statutes/section. `missing_session_law_id`: the URL names an
            endpoint where the id goes. `needs_jurisdiction`: the citation is in
            a form several states share and names none, so none was chosen for
            you; `jurisdictions` lists the states where it exists and
            `didYouMean` one law per state. `session_not_fully_collected`:
            nothing matched, and the session the id or citation points into is
            only partly collected, so the law may exist; `sessionCoverage` says
            how much of the session we hold. The route's price is never charged
            on a 404; a citation's resolution fee is kept on
            `unresolved_citation`, `ambiguous_citation` and
            `needs_jurisdiction`, and refunded on `session_not_fully_collected`:
            a miss in a partly collected session is never charged.
          examples:
            - not_in_registry
        didYouMean:
          items:
            type: string
          type: array
          title: Didyoumean
          description: >-
            Real `sessionLawId`s the input points at: the one that exists in a
            different case, or every law an ambiguous citation names (at most
            20, the conventional reading first). Empty when nothing matched.
          examples:
            - - SSL_KY_2025R_G_Y2025_C100
              - SSL_MO_2025R_G_Y2025_BHB2
        defaultSessionLawId:
          anyOf:
            - type: string
            - type: 'null'
          title: Defaultsessionlawid
          description: >-
            On `ambiguous_citation`, the conventional reading when the registry
            records one, otherwise null. Informational: it is never served for
            you.
          examples:
            - null
        jurisdictions:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Jurisdictions
          description: >-
            On `needs_jurisdiction`, every state (lower-case postal code) where
            the citation you sent exists. Name one of them in the citation and
            send it again. Absent on every other reason.
          examples:
            - - il
              - mn
              - tx
        candidateCount:
          anyOf:
            - type: integer
            - type: 'null'
          title: Candidatecount
          description: >-
            On `ambiguous_citation` and `needs_jurisdiction`, how many laws the
            citation names in all. Compare it with `len(didYouMean)`: when it is
            larger, `truncated` is true and the list is a sample, not the full
            set.
          examples:
            - 22
        truncated:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Truncated
          description: >-
            True when `didYouMean` was capped (at most 20 ids) and
            `candidateCount` is larger than the list. Absent on reasons that
            carry no candidates.
          examples:
            - true
        sessionCoverage:
          anyOf:
            - $ref: '#/components/schemas/SessionLawSessionCoverage'
            - type: 'null'
          description: >-
            On `session_not_fully_collected`, the partly collected session the
            id or citation points into: how many laws we hold of how many it is
            expected to have (`denominator`), and how many are still open.
            Absent on every other reason. The same block is in
            `sessionLaws.sessions` on `GET /us/statutes/coverage`.
      type: object
      required:
        - detail
        - sessionLawId
        - reason
      title: SessionLawNotFoundError
      description: The 404 from `GET /us/session-laws/{sessionLawId}` and its `/body`.
    SessionLawSession:
      properties:
        code:
          type: string
          title: Code
          description: >-
            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`.
          examples:
            - 2025R
            - 2025S1
        label:
          anyOf:
            - type: string
            - type: 'null'
          title: Label
          description: The session's canonical label, as the publisher names it.
          examples:
            - 2025 Regular Session
            - 2025 1st Special Session
        type:
          anyOf:
            - type: string
            - type: 'null'
          title: Type
          description: >-
            `regular`, `special`, `extraordinary`, `fiscal`, `veto` or
            `unknown`.
          examples:
            - regular
        year:
          anyOf:
            - type: integer
            - type: 'null'
          title: Year
          description: The year the session convened, the same year `code` starts with.
          examples:
            - 2025
      type: object
      required:
        - code
      title: SessionLawSession
      description: The legislative session a law was enacted in.
    ApiFieldError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Loc
          description: >-
            Where the bad value is: `body`, `query` or `path`, then the
            parameter name exactly as you send it (camelCase), then list
            indexes. A bare `["body"]` means the body as a whole was not a JSON
            object.
          examples:
            - - body
              - corpusType
        msg:
          type: string
          title: Msg
          description: What is wrong with the value, in plain English.
          examples:
            - Input should be 'USC', 'CFR' or 'STATE'
        type:
          type: string
          title: Type
          description: >-
            Machine-readable error kind, e.g. `missing`, `literal_error`,
            `json_invalid`.
          examples:
            - literal_error
      type: object
      required:
        - loc
        - msg
        - type
      title: ApiFieldError
      description: One rejected field in a 422 response.
    SessionLawSessionCoverage:
      properties:
        code:
          type: string
          title: Code
          description: Session code, for example `2025R`.
          examples:
            - 2025R
        label:
          anyOf:
            - type: string
            - type: 'null'
          title: Label
          description: The session's canonical label.
          examples:
            - 2025 Regular Session
        type:
          anyOf:
            - type: string
            - type: 'null'
          title: Type
          description: >-
            `regular`, `special`, `extraordinary`, `fiscal`, `veto` or
            `unknown`.
          examples:
            - regular
        year:
          anyOf:
            - type: integer
            - type: 'null'
          title: Year
          description: The year the session convened, the year `code` starts with.
          examples:
            - 2025
        status:
          type: string
          enum:
            - complete
            - partial
          title: Status
          description: >-
            `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.
          examples:
            - complete
        servedCount:
          type: integer
          minimum: 0
          title: Servedcount
          description: >-
            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.
          examples:
            - 39
        withheldCount:
          type: integer
          minimum: 0
          title: Withheldcount
          description: >-
            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.
          default: 0
          examples:
            - 0
        notHeldCount:
          type: integer
          minimum: 0
          title: Notheldcount
          description: >-
            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`.
          default: 0
          examples:
            - 0
        registryCount:
          type: integer
          minimum: 0
          title: Registrycount
          description: >-
            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.
          default: 0
          examples:
            - 39
        collectedCount:
          type: integer
          minimum: 0
          title: Collectedcount
          description: >-
            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.
          default: 0
          examples:
            - 39
        denominator:
          anyOf:
            - $ref: '#/components/schemas/SessionLawDenominator'
            - type: 'null'
          description: >-
            How many laws the session is expected to hold, and where that figure
            comes from. Null when it could not be read.
          examples:
            - derivation: >-
                The publisher's complete listing of this session names 296
                measures. We hold 43 of them; the rest are not yet collected.
              kind: complete_listing
              value: 296
        openGaps:
          type: integer
          minimum: 0
          title: Opengaps
          description: >-
            Laws the publisher lists for this session that we could not collect
            and have not yet. 0 on a `complete` session.
          default: 0
          examples:
            - 0
        measuredAt:
          anyOf:
            - type: string
            - type: 'null'
          title: Measuredat
          description: When this session's coverage was last measured, ISO 8601 UTC.
          examples:
            - '2026-10-05T09:07:12+00:00'
      type: object
      required:
        - code
        - status
        - servedCount
      title: SessionLawSessionCoverage
      description: One legislative session's session-law coverage.
    SessionLawDenominator:
      properties:
        kind:
          type: string
          enum:
            - stated_count
            - complete_listing
            - max_number
            - feed_total
            - our_recount
            - registry_union
            - none
          title: Kind
          description: >-
            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.
          examples:
            - complete_listing
        value:
          anyOf:
            - type: integer
              minimum: 0
            - type: 'null'
          title: Value
          description: >-
            The number of laws the session is expected to hold. Null when `kind`
            is `none`. Compare it with `registryCount` and `servedCount`.
          examples:
            - 296
        derivation:
          type: string
          title: Derivation
          description: >-
            One plain sentence saying what `value` counts and where it comes
            from. Written for customers: it never contains our internal audit or
            collection notes.
          examples:
            - The publisher's complete listing of this session names 296 acts.
      type: object
      required:
        - kind
        - derivation
      title: SessionLawDenominator
      description: >-
        How many laws a session is supposed to hold, and where that number comes
        from.
  securitySchemes:
    ApiKeyAuth:
      type: http
      scheme: bearer
      bearerFormat: vq_key_*
      description: >-
        API key issued from the developer dashboard. Pass as `Authorization:
        Bearer vq_key_...` (preferred).
    ApiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        The same API key as a bare header value: `X-API-Key: vq_key_...`.
        Equivalent to the Bearer form.
    ApiKeyQuery:
      type: apiKey
      in: query
      name: api_key
      description: >-
        The same API key as a query parameter: `?api_key=vq_key_...`. Use only
        where you cannot set a header. A URL can end up in proxy and server
        logs, browser history and shared links, so prefer either header form,
        and rotate a key that has leaked.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.