US Session Laws

List a state's session laws

List the session laws of one state: every act its legislature enacted, filtered by session, approval date or effective date. This is how you ask "what became law in Texas this session", "what was signed in April" or "what takes effect on September 1, 2025", and how you turn the answer into sessionLawIds for the get and body endpoints. A session law is the act as enacted, before it is folded into a code; v1 serves STATE acts.

Cost: 1 credit per page of up to 200 rows (default 50), however many rows the page holds. An empty page is an answer and is charged when it means nothing matches your filters. A request that fails validation (422) is never charged; a failure on our side (500, 503) is refunded.

Empty pages. A page with no rows carries coverage, what we hold of the session you named (or of the state, when you named none), so you can tell "nothing matches" from "we have not collected this". coverage.status is complete (we hold every law the publisher lists for it: the empty page is a true negative, and it is charged), partial (the collection stopped short, so the law you want may exist) or not_held (we hold nothing of it). On partial and not_held the page is NOT charged and creditsConsumed is 0: we do not bill an empty answer that may be our gap. The one exception is a request that names only the state, where some sessions we hold are complete and some partial: the page is charged, since for the complete ones it is a true negative, and coverage.partialSessions names the sessions to doubt (send one as session to ask about it alone). If coverage cannot be read the page is charged as before and coverage is omitted.

Filters. jurisdiction is required and scopes everything; the rest narrow it and combine with AND. A value that is malformed is a 422, and so is a range whose end is before its start (approvedTo before approvedFrom, effectiveTo before effectiveFrom). A value that is well formed and matches nothing (an unknown session, a date range with no laws) is a 200 with results: []. Dates are YYYY-MM-DD.

  • Everything from one session: session (2025R, 2025S1).
  • Approved in a window: approvedFrom / approvedTo.
  • Taking effect in a window: effectiveFrom / effectiveTo. For one day send the same date to both. This matches laws whose first-to-last effective dates overlap your window, so read effectiveFirst and effectiveLast on each row and effectiveDates on the law. A law with no held effective date (not every state prints them) never matches.
  • Narrow by series, instrumentType, hasText or textStatus.
  • What became law and what did not: isLaw (false for the vetoed and pocket-vetoed measures; a measure whose outcome does not settle it has a null isLaw and matches neither value) and enactmentOutcome, repeated for several outcomes (enactmentOutcome=vetoed&enactmentOutcome=pocket_veto).
  • A sync job: updatedSince returns the laws whose record changed on or after a date (midnight UTC, by updatedAt), so a job that stores its last run pulls only what is new or corrected.
  • Find by words: q, a case-insensitive substring of the title or the bill number as the publisher prints it (3 to 100 characters). It is a substring match inside one state, not a search engine.
  • A derived approval date (approvedDateDerived: true) is not matched by approvedFrom and approvedTo, which read the registry's own approval date.

Paging. Rows come in session.code order, then sessionLawId, both as TEXT in the database's collation, not in chapter order: ..._C10 sorts before ..._C2, and the id's series and numbering-year segments sort before the chapter. Sort client-side by number if you need chapter order. The order is the same on every page and for every filter, so a cursor never skips or repeats a row. Send nextCursor back as cursor, with the same filters, while hasMore is true (a cursor sent with different filters is a 422, cursor_query_mismatch: restart without it). The cursor is a keyset (it names the last row you saw), so laws added between your calls never repeat or skip a row you have passed. count is the size of this page, never a total.

Text. Rows include laws whose text we do not hold (textStatus: not_held) or hold and withhold (withheld, with withheldReason): the row is still a real law. Pass hasText=true for just the laws /{sessionLawId}/body will serve. A row is the summary only: the full dates, sources and code sections are on GET /us/session-laws/{sessionLawId}. Each row carries charCount and estimatedBodyPages, so you can price reading a law before you open it. citableAs is the law cited the way a lawyer writes it (Minn. Laws 2025, ch. 1), and licenseNote says what its licence class permits.

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.

Example

curl "https://api.vaquill.ai/api/v1/us/session-laws/list?jurisdiction=tx&effectiveFrom=2025-09-01&effectiveTo=2025-09-01&limit=25" \
  -H "Authorization: Bearer $VAQUILL_API_KEY"

# only what changed since your last sync, and only measures that did not become law
curl "https://api.vaquill.ai/api/v1/us/session-laws/list?jurisdiction=mn&updatedSince=2026-10-01" \
  -H "Authorization: Bearer $VAQUILL_API_KEY"
curl "https://api.vaquill.ai/api/v1/us/session-laws/list?jurisdiction=mn&isLaw=false&enactmentOutcome=vetoed&enactmentOutcome=pocket_veto" \
  -H "Authorization: Bearer $VAQUILL_API_KEY"

# find by words in the title or the printed bill number
curl "https://api.vaquill.ai/api/v1/us/session-laws/list?jurisdiction=mn&q=court%20fees" -H "Authorization: Bearer $VAQUILL_API_KEY"
const url = new URL("https://api.vaquill.ai/api/v1/us/session-laws/list");
url.search = new URLSearchParams({ jurisdiction: "mn", session: "2025R" });
const res = await fetch(url, {
  headers: { Authorization: `Bearer ${process.env.VAQUILL_API_KEY}` },
});
const { results, nextCursor, hasMore } = await res.json();

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.

get/api/v1/us/session-laws/list

Request

Query parameters

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' required

Two-letter code of the state whose session laws to list: the 50 states, dc and pr. Case-insensitive (MN works). Required: the list is scoped to one jurisdiction at a time. federal and any unknown code is a 422; federal session laws are on /us/statutes/section. A jurisdiction we hold no session laws for returns an empty page with a coverage block saying so, which is not charged: see sessionLaws on /us/statutes/coverage for what is held.

Example:mn
sessionstring nullable

Only laws enacted in this session. Use the code exactly as session.code reports it: 2025R is the 2025 regular session, 2025S1 the first special session of 2025. Case-sensitive, so 2025r matches nothing. A code that matches no session returns an empty page (charged), not an error; characters other than letters, digits, ., _ and - are a 422. Omit to list every session.

Example:2025R
seriesstring[] nullable

Only laws in one of these numbering series. Repeat the parameter for several (series=resolve&series=resolves); they combine with OR. general is the ordinary chapter sequence of most states; others number acts, resolutions or local laws apart. One of general, public, public_act, special_act, private_and_special, act, acts, law, local, municipal, appropriation, resolve, resolves, resolution, resolution_chapter, joint_resolution, concurrent_resolution, memorial, initiated_bill, constitutional_amendment, private, constitutional_resolution, competing_measure_resolution, resolution_act, as a result's series reports it. Not every jurisdiction uses every series: sessionLaws on /us/statutes/coverage lists each one's. Any other value is a 422, never charged; a valid series nothing matches returns an empty page (charged). Omit for every series.

[
  "general"
]
instrumentTypestring[] nullable

Only these kinds of measure. Repeat the parameter for several (instrumentType=joint_resolution&instrumentType=concurrent_resolution); they combine with OR. One of act, joint_resolution, concurrent_resolution, resolution, resolve, memorial, other (act is an ordinary law), as instrumentType reports it. Any other value is a 422, never charged; a valid kind nothing matches returns an empty page (charged). Omit for every kind.

[
  "joint_resolution",
  "concurrent_resolution"
]
approvedFromstring date nullable

Only laws approved (signed) on or after this date. Format YYYY-MM-DD, inclusive; it must be a real calendar date (2025-02-30 is a 422). A law with no printed approval date never matches, and neither does one whose approvedDate we derived (approvedDateDerived: true): this filter reads the registry's own approval date, so South Dakota's derived dates are not found by it. Pair with approvedTo for a range; an end before the start is a 422 (never charged).

Example:2025-04-01
approvedTostring date nullable

Only laws approved (signed) on or before this date. Format YYYY-MM-DD, inclusive; it must be a real calendar date (2025-02-30 is a 422). Like approvedFrom, it does not match a derived approvedDate.

Example:2025-05-31
effectiveFromstring date nullable

Only laws with an effective date on or after this date. Format YYYY-MM-DD, inclusive; it must be a real calendar date (2025-02-30 is a 422). A law matches when the span from its first to its last effective date (effectiveFirst to effectiveLast) overlaps your window, so one whose dates straddle your day is returned even though none falls exactly on it: read effectiveDates on the law for the dates themselves. Only laws with a held effective date can match, and not every state's publisher prints them (Texas, Washington and Iowa do; Minnesota does not yet): a law with no effective date is never returned by this filter, though it may well be in force. To get everything taking effect on one day, send the same date to both effectiveFrom and effectiveTo; for example jurisdiction=tx, effectiveFrom=2025-09-01, effectiveTo=2025-09-01 lists the Texas acts effective September 1, 2025.

Example:2025-09-01
effectiveTostring date nullable

Only laws with an effective date on or before this date. Format YYYY-MM-DD, inclusive; it must be a real calendar date (2025-02-30 is a 422). Overlap rule as for effectiveFrom. An end before effectiveFrom is a 422 (never charged).

Example:2025-09-30
hasTextboolean nullable

true: only laws whose text is served (textStatus: held), the ones /{sessionLawId}/body will return. false: only laws whose text is not served (withheld, not_held or pending). Omit for both. Combined with textStatus by AND, so hasText=true&textStatus=withheld is always empty. Anything but a boolean is a 422.

Example:true
textStatus'held' | 'withheld' | 'not_held' | 'pending' nullable

Only laws with this text status. One of held, withheld, not_held, pending: held is served, withheld is held but kept back for a measured defect, not_held is known to exist without text, pending is collected and not yet verified. Any other value is a 422. Omit for every status.

Example:held
isLawboolean nullable

true: only measures that are law. false: only numbered measures that are NOT law (a vetoed bill, a pocket veto), the ones isLaw: false marks. Omit for both. A measure whose outcome does not settle it (not_presented, unknown) has a null isLaw, so it matches neither true nor false: use enactmentOutcome for those. Anything but a boolean is a 422.

enactmentOutcomestring[] nullable

Only laws with one of these outcomes. Repeat the parameter for several (enactmentOutcome=vetoed&enactmentOutcome=pocket_veto); they combine with OR. One of signed, became_law_without_signature, veto_overridden, line_item_veto, vetoed, pocket_veto, not_presented, approved_by_voters, unknown, as enactmentOutcome reports it. Any other value is a 422, never charged; a valid outcome nothing matches returns an empty page (charged). The order you send them in does not matter, and a cursor stays valid for the same set.

[
  "vetoed",
  "pocket_veto"
]
updatedSincestring date nullable

Only laws whose record changed on or after this date, midnight UTC, by updatedAt: the filter for a sync job that pulls only what is new or corrected since its last run. Format YYYY-MM-DD, inclusive; it must be a real calendar date (2025-02-30 is a 422). A day with no change returns an empty page (charged), not an error.

Example:2026-10-01
qstring nullable

Only laws whose title or printed billNumber contains this text, case-insensitively (grain buyers finds An act relating to agriculture; modifying financial reporting requirements for grain buyers ...). A plain substring, not a search engine: no stemming, no ranking, and % and _ mean themselves. The bill number is matched as the publisher prints it (S.F.No. 1552, not SF 1552): to find a law by citation, use GET /us/session-laws/{sessionLawId}. 3 to 100 characters after trimming and without control characters, else a 422 (never charged); text that matches nothing returns an empty page (charged). Combines with the other filters by AND within the required jurisdiction.

Example:grain buyers
cursorstring nullable

Where to resume: the previous page's nextCursor, unchanged. Send it with the same filters that produced it (limit may change). It is opaque, signed and tied to those filters, and is only ever issued by this API: a value we did not issue is a 422 with reason: invalid_cursor, one from an older cursor format is cursor_expired, and one sent with different filters is cursor_query_mismatch (restart without cursor). Never an empty page. Omit for the first page.

Example:eyJ2IjoyLCJqIjoibW4iLCJzIjoiMjAyNVIiLCJpIjoiU1NMX01OXzIwMjVSX0dfWTIwMjVfQzEwIiwicSI6IjYxMjk2NDEzOTE2OTJmOTYifQ.86d0NXnVAJD7j_3d9zoWPQ
limitinteger

Rows per page, 1 to 200; default 50. A page costs the same however many rows it holds, so a larger limit is cheaper per law. Outside the range is a 422.

Example:25

Headers

Idempotency-Keystring nullable

Optional. 16 to 255 visible ASCII characters (a UUIDv4 is ideal). A retry with the same key and the same request replays the original 2xx response for 24 hours without charging again. The same key with a different request is rejected. Scope is the API key, method, path and body. The stored response body is a query-derived cache controlled by the account's data retention setting cacheQueryDerivedData: when it is false the body is never stored and a retry answers 409 idempotency_replay_unavailable, without charging again.

Example:3f9c2a1e-7b44-4d0a-9c1e-5a6b7c8d9e0f

Response

A page of the state's session laws. hasMore and nextCursor say whether another follows; an empty results is a charged answer, unless coverage says the session or state is not fully collected.

processingTimeMsnumber

Server-side time for this request in milliseconds, excluding network transit. Not billed on.

creditsConsumedinteger

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).

countinteger

Rows on this page. Never a total: the list is paged by cursor and has no corpus-wide count.

nextCursorstring nullable

Opaque cursor for the next page: send it as cursor, with the same filters. Null on the last page.

hasMoreboolean

True when another page follows. Each page is charged, an empty one included, except an empty page that coverage reports as a gap in our collection.

Example response

{
  "processingTimeMs": 747.5,
  "creditsConsumed": 2,
  "results": [
    {
      "sessionLawId": "SSL_MN_2025R_G_Y2025_C1",
      "jurisdiction": "mn",
      "citation": "CHAPTER 1--S.F.No. 1552",
      "citableAs": "Minn. Laws 2025, ch. 1",
      "citationShort": "MN ch. 1 (2025)",
      "session": {
        "code": "2025R",
        "label": "2025 Regular Session",
        "type": "regular",
        "year": 2025
      },
      "series": "general",
      "instrumentType": "act",
      "number": "1",
      "billKey": "HB2",
      "billNumber": "S.F.No. 1552",
      "numberingYear": 2025,
      "title": "An act relating to agriculture; modifying financial reporting requirements for grain buyers; amending Minnesota Statutes 2024, section 223.17, subdivision 6.",
      "shortTitle": "Enact Advance Ohio Higher Education Act",
      "approvedDate": "2025-03-17",
      "effectiveFirst": "2025-09-01",
      "effectiveLast": "2026-01-01",
      "enactmentOutcome": "signed",
      "isLaw": true,
      "textStatus": "held",
      "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.",
      "charCount": 5470,
      "estimatedBodyPages": 1,
      "textSha256": "55c7a8d08647e41f87e23fc2016881a6583911a1d5cfa8687403442e9096451b",
      "versionNo": 1,
      "amendatoryMarkup": "preserved",
      "markupConvention": "publisher_literal",
      "documentKind": "session_law_print",
      "identityConfidence": "single_source",
      "officialUrl": "https://www.nysenate.gov/legislation/bills/2025/A414",
      "officialUrlBasis": "bill_page",
      "licenseNote": "Government public: published by a government body with no restrictive terms, so the text may be reused, including commercially.",
      "updatedAt": "2026-10-05T09:06:39.998043+00:00"
    }
  ],
  "count": 25,
  "nextCursor": "eyJ2IjoxLCJqIjoibW4iLCJzIjoiMjAyNVIiLCJpIjoiU1NMX01OXzIwMjVSX0dfWTIwMjVfQzEzIn0",
  "hasMore": true,
  "coverage": {
    "scope": "session",
    "jurisdiction": "ok",
    "status": "complete",
    "session": {
      "code": "2025R",
      "label": "2025 Regular Session",
      "type": "regular",
      "year": 2025
    },
    "sessionsHeld": 1,
    "partialSessions": [
      "2025R"
    ],
    "reason": "We have not collected this jurisdiction's session laws yet.",
    "message": "No law in this session matches your filters. We hold every law the publisher lists for 2025R, so this is not a gap in our collection."
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.