Skip to main content
A few habits make Vaquill AI integrations faster, cheaper, and more accurate. Follow these when you move from a prototype to production.

Scope every query

Pass corpusType (and state for state-scoped corpora) on POST /us/statutes/search. Scoping does two things: it sharpens relevance by removing off-target jurisdictions, and it makes your pages more predictable. An unscoped search ranks across the whole corpus, so a state-specific answer can be crowded out by federal or other-state matches.
You can scope tighter still. code (state, e.g. tx_pe) and titleNumber (USC/CFR) narrow a search to one code or title. Get a state’s code values from GET /us/statutes/divisions?corpusType=STATE&state=XX. To go one level deeper, chapter (USC/state) and part (CFR) confine a search to a single subtree. These are the search-side of the parent object on every result: take a hit’s parent and pass it straight back to search that section’s neighbors. chapter/part must be paired with titleNumber or code (which parent always carries), since a chapter number alone repeats across every title.

Choose the right matchType

matchType is the exact-match control in the API, and it is what you reach for when hybrid ranking is too loose. any ranks on intent, so a query can rank a section that shares no wording with it. That is what you want for “how long does a landlord have to return a deposit”, and wrong for “material adverse effect”, where a section that merely discusses the idea is noise. all and phrase trade recall for precision. Both can return nothing. An empty result under them means no section we ranked for your query carried those terms, which is not the same as the corpus holding none, so fall back to any and scope the query more tightly rather than concluding there is a coverage gap.
boolean is the one to use when the logic matters: one term or another, a term excluded, two terms in the same sentence. Write operators in uppercase and always write AND out, because a space between words makes a phrase. Read parsedQuery on the response to see how the expression was grouped. A malformed expression is a 422 that names the problem and is not charged.
To pull up one specific section, pass its citation as the query (for example 42 U.S.C. § 1983) and leave matchType at any. It resolves to that section at rank 1. GET /us/statutes/resolve does the same job for less when you already hold a well-formed citation.

Control what a search returns

  • excerptChars: how much matching text each result carries (default 500, up to 4000). The excerpt is windowed around the match and can begin mid-section, dropping a leading subsection marker, so it is a ranking preview and not safe to quote.
  • includeBody: attaches each hit’s full text on body in the same call. It bills each row that returns text on top of the search, so it multiplies with limit. Use it with a small limit, and read creditsConsumed.
For text you intend to quote, use body or GET /us/statutes/section/{actId}/body, never a raised excerptChars. Each result also carries a parent object: the /us/statutes/divisions query that lists the section’s siblings, so you can walk up the hierarchy from any hit. Section responses also include amendment provenance (sourceCredit, amendmentYears, lastAmendedYear, publicLaws, federalRegisterCitations). Two endpoints answer everything about what is queryable.
  • GET /us/statutes/coverage is the corpus matrix. Read a jurisdiction’s corpora keys and pass one back as corpusType. This avoids guessing a token that has no data for that state and wasting a call on an empty result.
  • GET /us/statutes/divisions is the hierarchy. Pass corpusType=STATE&state=XX to list a state’s individual statutory codes (Penal, Civil, and so on) and their code values, or drill in with titleNumber, code, chapter and part.

Cache coverage

Coverage grows weekly, not hourly. Cache /us/statutes/coverage and /us/statutes/divisions for hours or a day rather than calling them on every request. They still count against your rate limits.

Store the actId values you care about

The actId (for example USC_T42_C21_S1983) is the handle for a section. Once a search surfaces a section your product depends on, store its actId and go straight to GET /us/statutes/section/{actId} or .../body on later runs. That skips the search entirely. Store the citation next to it. An actId survives an amendment and a repeal, but it changes if the section is renumbered, so a lookup that stops resolving is a cue to re-resolve by citation through GET /us/statutes/resolve rather than to drop the record. See Section identifiers.

Retry on 429, handle 402

  • On 429, respect the Retry-After header and use exponential backoff. See Errors.
  • On 402, stop, surface a clear message, resolve it in your account dashboard, then retry.
  • Both are expected in production. Build for them rather than treating them as fatal.

Treat relevanceScore as a within-response rank

relevanceScore (0 to 1) orders results within a single response. It is a relative rank, not a calibrated confidence score. Do not compare scores across different queries and do not use a fixed threshold (for example “drop anything below 0.7”) to decide what to keep. To narrow results, tighten query, corpusType, and state instead. To tell whether the corpus has anything on point at all, read noGoodMatch on the search response instead of thresholding scores yourself:
  • true: nothing in the corpus looks on point for this query (or no rows came back). Say so, rather than presenting the rows as an answer.
  • false: something on point was found, or the top row is an exact citation match.
  • null: the ranking was degraded (rankingDegraded: true), so its scores cannot be judged. Retry the query.
To judge how likely the top result is to be the right section, read matchQuality: The tiers are measured on our labelled evaluation set and may be re-cut as the index changes. Treat a value you do not recognise as moderate. noGoodMatch and matchQuality are properties of the query, so every page of one search carries the same values. It says nothing about whether the top result is the right section. A same-topic section from the wrong jurisdiction or the wrong layer (a state statute for a federal question, a regulation for a statute) can rank first, so check citation and state before you rely on it. Browse is ordered differently. GET /us/statutes/divisions returns divisions in statutory (natural) order, the way a person reads a code, not by relevance: 9 sorts before 10, and 240.9 before 240.10. Reach for search when you want the most on-point section, and for browse when you want the structure in order. Each result carries source links (htmlUrl, pdfUrl, xmlUrl, textUrl, docxUrl, stateHtmlUrl, govInfoHtmlUrl, govInfoPdfUrl, externalUrl; any may be null). For user-facing deep links, prefer the official government link (state legislature or govinfo.gov) so readers land on authoritative text. This keeps your product grounded and verifiable.

Pagination

Page predictably with limit, offset, and hasMore.

Coverage

See the full jurisdiction and corpus matrix.
Last modified on October 21, 2026