Get statute full text
Get the full text of a statute section in HTML and plain text.
Cost: 6 credits. You are only charged when text is returned: not-found (404), failed fetches, sections whose text is not yet ingested (available: false) and sections the publisher prints as images (bodyUnavailable: true) are all refunded.
Works across USC, CFR, and state corpora. The text preserves formatting, cross-references, and paragraph numbering as published in the official source.
Response: available: true with html + plain, or available: false with a note and creditsConsumed: 0 when the full text is not yet ingested (metadata is still available from /us/statutes/section/{actId}).
A section with no text to return. Some sections (appendices, forms and maps) are printed by the publisher as images, so there is nothing to extract. They answer available: false, plain and html null, bodyUnavailable: true, bodyUnavailableReason: "image_only_source", a note and creditsConsumed: 0. Both fields are omitted on every other section. This is a final answer, not a failure to retry: the section exists and its metadata is complete. Where we hold an official link for it, sourceUrl carries it; it is null where we may not republish the publisher's link. Search rows, includeBody and the batch /sections route carry the same two fields, with body null and no body charge for that row.
sourceUrl is where the government published this text: cite and verify against that, not against source, which names our storage backend. It is null when we hold no official link for the section; only government links are served.
Tables and figures (markdown / tables / figures)
Where a section has a structured rendering, source is r2_render and the body keeps what a flat text extraction loses: tables as real tables and images at the position the publisher prints them.
- html -- <table> elements with <caption>, colspan and rowspan, and <figure> / <img> elements whose images are hosted on statutes-us.vaquill.ai
- markdown -- GitHub-flavoured Markdown, tables as pipe tables and figures as 
- plain -- tables as one tab-separated line per row, figures as [Figure N: caption] placeholders
- tables / figures -- what the body contains, in document order. Each figure carries its hosted url and its offset into markdown and plain, so you can place images in your own layout. A figure we could not fetch is listed with status: "unavailable" and keeps its caption in the text.
- hasTables / hasFigures -- quick flags
A section in a covered corpus that has no table and no figure returns tables: [], figures: [] and both flags false, with its text in html and plain as before. Where a corpus has no structured rendering yet, those fields are null, meaning "not known", not "none": a table may still be present in html. markdown is returned only for format=all or format=markdown: the default format=both leaves it out, because it is a third full copy of the text. format=markdown returns only markdown, and falls back to plain with a note when the section has no structured rendering. The price is the same whichever format you ask for.
Telling the law from the apparatus (content / sourceCredit / notes)
plain and html are the WHOLE body as the publisher prints it: the operative text, then the source credit, then the notes apparatus (historical and revision notes, committee reports, editorial notes, amendments, effective-date notes).
For United States Code sections that body is mostly not the law: measured 2026-09-02, the operative text is a median 46% of it across USC, and as little as 3.4% on 17 U.S.C. § 107.
So the granule is split into three additional fields, using the field delimiters GPO publishes in the source:
- content -- the operative text, and nothing else
- sourceCredit -- the credit line, e.g. (Pub. L. 94-553, ...)
- notes -- the apparatus, kept because it is the legislative history
Use content if you are feeding sections to a model: the full body invites it to quote a 1992 amendment note as the law in force.
Two format values act on the split, and the difference between them is how many bytes cross the wire, not what the law says:
- format=content drops plain/html and returns all three split fields. The apparatus is still on the response, because for a legislative-history or effective-date question it IS the answer.
- format=operative drops notes as well, returning content + sourceCredit and nothing else. Measured on 17 U.S.C. § 107: 95,217 bytes at both, 61,003 at plain, 30,545 at content, 1,564 at operative. Same 6 credits either way -- the fetch is identical, so this buys bandwidth and prompt budget, not a discount.
Reach for operative when you are putting the law in front of a model or a reader and the notes are noise. Reach for content when you may need to read the apparatus but want to keep it clearly separated from the law.
⚠️ USC only. CFR and the state corpora carry no equivalent structure in their sources, so all three fields are null there and plain remains the whole body. Null means "we cannot split this reliably", never "this section is empty". Both content and operative fall back to serving plain with an explanatory note on a corpus that cannot be split, rather than returning a response that claims to carry the text and does not.
Pass structured=true to also get markdown (the body as nested Markdown lists) and subsections (a tree you can address by pincite, e.g. (b)(2), each node carrying its pincite path and full pinpoint citation). Same cost.
One subsection (pinpoint)
Pass pinpoint=(c)(1) to get that unit in the pinpoint field, alongside the whole body, for the same price. Write the pinpoint as parenthesised labels, outermost first, without the section number: (c), (c)(1), (d-1), (f)(1.5). A label that contains a hyphen or a dot is one label, so (f)(1.5) is the path ["f", "1.5"]. Anything else is a 422 and is not charged.
pinpoint carries the unit's own text (text), the unit with everything beneath it as printed (fullText), each ancestor's own text (leadIn, so (c)(1) can be read as the sentence it completes), the units directly beneath it (children), the labels either side of it (siblings) and its character range in plain (charStart, charEnd). Read matched first. A pinpoint the section does not contain is matched: false with a reason and, in available, the labels that do exist at the level where the lookup stopped; matchLevel: ancestor means only the leading part of your pinpoint exists and the block describes the deepest unit that does (unmatched is the rest). A section whose outline we could not recover answers reason: no_structure.
structure says where the outline came from: a stored artifact that was checked against the exact text returned here, or request_time parsing, and its quality. structured and pinpoint are independent and can be combined: structured returns the whole tree in subsections, pinpoint returns one unit in pinpoint. When a stored outline exists both come from it. pinpoint cannot be combined with asOf (the historical text is plain and carries no outline): that is a 422.
Point-in-time (asOf)
Pass asOf=YYYY-MM-DD to get the text as it stood on that date instead of today's. Same cost.
One parameter, two engines, and asOf.engine says which one answered. Read it before anything else in the block, because the two make different promises and isBounded does not mean the same thing under each.
engine: "stored_edition" -- we hold the publisher's own printed editions for this corpus and return one verbatim. CFR annual editions, the US Code, the Copyright Compendium and OFAC FAQs. Here isBounded: true means your date fell inside an edition we actually hold, which is a verified published printing.
Coverage under this engine is ENUMERATED, not continuous, and outside the CFR annual editions it is currently sparse. A date in a gap between two held editions returns source: "unavailable", isBounded: false, no text, and an outOfCoverageReason naming what we do hold. It is never answered from a neighbouring edition, because the text may have changed in the gap. For the US Code this is the common case today: most historical dates fall between the editions we hold and are reported out of coverage, with outOfCoverageReason naming the editions that are available. Do not read the presence of this parameter as full US Code point-in-time coverage.
engine: "observed_change" -- every other corpus. A reconstruction, not an archive. The corpus holds one current text per citation; an earlier one is rebuilt from the before-side of the first change we OBSERVED after your date, through the same resolver the watch diff uses. Here isBounded: true is the WEAK claim, described below.
The asOf block reports:
- source -- on observed_change: live (nothing captured after your date AND the text we hold took effect on or before it, so today's text stood then), reconstructed, or unavailable. On stored_edition: published or unavailable
- outOfCoverageReason -- why no text came back, when none did
- currentVersionEffective / earliestHeldVersion -- when the text we hold took effect, and the earliest version we hold. If your date PRECEDES the current text's effective date, today's text is never returned as the law on your date: you get a held prior version (engine: stored_edition, source: published) or source: unavailable with these two dates and NO text, refunded. A section that states no readable effective date and has no capture reaching your date returns today's text with a note saying it is unverified for that date
- basisChangeId -- the change event this answer rests on, readable at /us/statutes/section/{actId}/changes
- observedFrom -- how far back the evidence reaches for this section
- isBounded -- read this one, and read engine first. On observed_change, true means we observed no change affecting your date, which is not the same as there having been none: capture began long after the corpus did and is per-source. On stored_edition it is inverted and stronger, as above: true means a held edition governed your date.
html is never returned on this path: the text is plain, and synthesising markup the publisher never printed would be a wrong answer on the endpoint whose job is fidelity.
A section that did not exist on that date returns available: false with asOf.existed: false and IS charged, the same way an unresolved citation is charged on /resolve: a confident negative is the answer. On observed_change, a section we know changed but cannot rebuild returns source: "unavailable" and is refunded. On stored_edition, an out-of-coverage date is an ANSWER about what we hold and is charged, which is the same rule the CFR annual editions have always followed.
Request
- Base URLhttps://api.vaquill.ai
- Auth
- HTTP bearer
- or API key in header X-API-Key
- TypeScriptA function with typed inputs. Its response is checked against the schema.
Path parameters
Section identifier, e.g. USC_T42_C21_S1983 (Title 42, Chapter 21, Section 1983, which a lawyer writes as 42 U.S.C. § 1983). Take it from a /us/statutes/search or /us/statutes/resolve result.
A citation also works here: 26 U.S.C. § 1, 42 USC 1983 or Cal. Civ. Code § 1950.5 is resolved with the same resolver /resolve uses, and the section is served. A citation costs this endpoint's price PLUS the /resolve price (2 credits), charged as its own line whether or not it resolves, exactly as /resolve charges; that is the same total as calling /resolve and then this endpoint, in one round trip. An exact act_id costs only this endpoint's price. When a citation resolves, or when the id only matched after surrounding whitespace, quotes or a trailing period were removed, the response carries resolvedFrom saying what your input was matched as. Check it the way you would check a /resolve answer. A citation containing / cannot travel in a URL path segment; resolve it with GET /us/statutes/resolve instead.
Do not assemble an id from a citation: the title and section are derivable, but the CHAPTER is not, so USC_T26_S1 misses. A miss returns 404 with reason and, where the section exists under another id, didYouMean.
State session laws (acts as enacted, ids starting SSL_) are not code sections: read them at /us/session-laws/{sessionLawId}.
Query parameters
Which representations to return. both (the default) returns html and plain. A long section carries the same text twice that way, so plain or html alone roughly halves the payload. Cost is unchanged: the fetch is the same either way.
all adds markdown where the section has a structured rendering. It is opt-in because it is a third full copy of the text (about 600,000 extra characters on 49 CFR 172.101), which a model-facing client would pay for in tokens without asking.
markdown returns only markdown. On a section with no structured rendering it falls back to plain with a note saying so, never to an empty body. tables and figures are returned on every format, because they are small and describe the text you received.
content omits html and plain and returns the split fields (content, sourceCredit, notes).
operative omits notes as well, leaving content + sourceCredit: the law and what enacted it, and nothing else. This is the smallest representation of a section, and on a note-heavy section it is the difference between a payload that fits in a prompt and one that does not. Measured on 17 U.S.C. § 107: 95,217 bytes at both, 30,545 at content, 1,564 at operative, all for the same 6 credits.
Only United States Code sections can be split, so on any other corpus both values fall back to returning plain with a note saying why -- content will be null there, so read note rather than assuming the section was empty.
When true, also return a subsections tree parsed from the text for pincite addressing, and markdown as that tree rendered as nested Markdown lists. Same cost.
structured=true OWNS markdown: on every format, and on every source, markdown is the nested-list rendering, never the table-preserving rendering a r2_render section otherwise returns for format=all/markdown (a note says so when that happens). Ask without structured for the tables. With format=markdown the nested lists are returned alone, without html or plain.
The response's structure block says whether the tree came from a stored outline (checked against this exact text) or was parsed on this request. To fetch a single unit instead of the whole tree, use pinpoint.
Return one subsection in pinpoint, alongside the whole body. Parenthesised labels, outermost first, without the section number: (c), (c)(1), (d-1), (f)(1.5). A label containing a hyphen or a dot is a single label. Same cost. A malformed pinpoint, or one sent with asOf, is a 422 and is not charged.
Read pinpoint.matched before using the text: a subsection the section does not have is reported as matched: false, not answered with the whole section.
Return the section's text as it stood on this date (YYYY-MM-DD, for example 2026-01-15) instead of today's. Same cost. Cannot be combined with pinpoint (a 422, not charged): a historical text carries no subsection outline.
This is a reconstruction, not an archive. The corpus holds one current text per citation; an earlier one is rebuilt from the before-side of the first change we OBSERVED after your date. The asOf block on the response says which version you got (source), what it rests on (basisChangeId), how far back the evidence reaches (observedFrom), and whether the answer is bounded by when capture began rather than by the law (isBounded). Read isBounded before citing the text.
A section that did not exist yet returns available: false with asOf.existed: false, which is a real answer and is charged. A section we know changed but cannot rebuild returns source: "unavailable" and IS refunded, because you asked for a historical text and did not get one.
A date that does not exist on a calendar (2026-02-30) is a 422 and is not charged.
Headers
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.
Response
Successful Response
Example response
{
"actId": "USC_T42_C21_S1983",
"sourceUrl": "https://www.govinfo.gov/content/pkg/USCODE-2024-title17/html/USCODE-2024-title17-chap1-sec107.htm",
"content": "Notwithstanding the provisions of sections 106 and 106A, the fair use...",
"sourceCredit": "(Pub. L. 94-553, title I, §101, Oct. 19, 1976, 90 Stat. 2546)",
"notes": "Historical and Revision Notes\n\nhouse report no. 94-1476...",
"committeeNotes": [
{
"year": 2015,
"kind": "amendment",
"heading": "Committee Notes on Rules—2015 Amendment",
"effectiveDate": "2015-12-01",
"subdivisionsDiscussed": [
"(b)(1)",
"(c)"
]
}
],
"committeeNote1937Print": {
"document": "H.R. Doc. No. 588, 75th Cong., 3d Sess. (1938)",
"ruleNumber": "4",
"printedHeading": "Rule 4. Process.",
"verdict": "agrees"
},
"bodyUnavailable": true,
"bodyUnavailableReason": "image_only_source",
"tables": [
{
"tableId": "t1"
}
],
"figures": [
{
"figureId": "fig_3f2a9c0d1e4b5a67",
"url": "https://statutes-us.vaquill.ai/figures/9b2e...c41.gif",
"sourceUrl": "https://www.ecfr.gov/graphics/er13my11.020.gif",
"mimeType": "image/gif"
}
],
"subsections": [
{
"pincite": "(b)(2)"
}
],
"pinpoint": {
"requested": "(c)(1)",
"path": [
"c",
"1"
],
"label": "(1)",
"level": "paragraph",
"inferred": true,
"matched": true,
"matchLevel": "exact",
"leadIn": [
{
"path": [
"c"
],
"label": "(c)",
"text": "Unless a different limit is established under this Chapter, the limit is:"
}
],
"children": [
{
"path": [
"c",
"1"
],
"label": "(1)",
"level": "paragraph",
"inferred": true
}
],
"siblings": {
"previous": "b",
"next": "d"
},
"charStart": 1204,
"charEnd": 1873,
"kind": "range",
"reason": "no_such_subsection",
"structure": {
"source": "artifact",
"quality": "verified",
"builder": "ilga_html",
"textSha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}
},
"structure": {
"source": "artifact",
"quality": "verified",
"builder": "ilga_html",
"textSha256": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
},
"asOf": {
"requested": "2026-01-15",
"engine": "observed_change",
"source": "reconstructed",
"basisChangeId": 91,
"observedFrom": "2026-08-09T04:10:00Z",
"resolvedEditionYear": 2019,
"scheduledEditionYear": 2024,
"editionsObserved": [
2014,
2015,
2016
],
"currentVersionEffective": "2026-01-01",
"earliestHeldVersion": "2026-01-01"
},
"resolvedFrom": {
"input": "26 U.S.C. § 1",
"actId": "USC_T26_C1_S1",
"via": "citation",
"subsection": "(h)(11)",
"matchLevel": "container",
"container": {
"kind": "chapter",
"label": "U.S. Const. art. III",
"childCount": 12,
"children": [
{
"actId": "CONST_US_A3_S1",
"citation": "U.S. Const. art. III, § 1",
"status": "in_force"
}
]
},
"repair": {
"kind": "code_name",
"cited": "Jud. Ct. Acts Law",
"interpretedAs": "N.Y. Judiciary Law § 475",
"alternatives": [
{
"actId": "STATE_NY_FCT_S475",
"citation": "N.Y. Fam. Ct. Act § 475"
}
]
},
"registerReference": {
"citation": "36 Pa. Bull. 510",
"state": "il",
"kind": "page",
"ruleCount": 2
}
},
"processingTimeMs": 240.5,
"creditsConsumed": 4
}Changes
No recorded changes to this operation across all 1 revision of this API.