Skip to main content
POST /us/statutes/search accepts a terms-and-connectors expression when you send matchType: "boolean". It is the syntax used by the major legal research services: AND, OR, NOT, same-sentence and same-paragraph connectors, numeric proximity, wildcards, exact phrases and grouping.
Three guarantees hold for every Boolean search:
  1. Every result satisfies the expression, judged over the section’s full text, not over one excerpt or one passage.
  2. Results are ranked by relevance among the matches. The expression decides which sections qualify, and relevance decides their order.
  3. Nothing is silently loosened or misread. A malformed expression, an operator we do not support, or an out-of-bounds value is a 422 that names the problem and its character position, and it is not charged.

When to use Boolean instead of any

Boolean mode is a filter you control. If you want the API to infer intent from a question, stay on any. If you need to say exactly which sections qualify, and to be told when your expression cannot be read, use boolean.

Quick start

The response has the same shape as any search, plus parsedQuery:
Paging, filters (state, corpusType, code, titleNumber, chapter, part, yearFrom, yearTo, excludeRepealed and the rest) and includeBody work exactly as they do for any search. The scope filters narrow the corpus first, and the expression is judged inside that scope.

Operators

Word operators are UPPERCASE. Lowercase and, or and not are ordinary words. Some details that matter in practice:
  • Distance counts word positions. /1 means adjacent, and notice /3 termination matches “notice of the termination” (three positions apart) but /2 does not.
  • atleastN( ) and atmN( ) take one term, phrase or wildcard: atleast3("trust fund"), atleast2(retaliat*).
  • Matching is on whole words, case-insensitively, with no stemming and no synonyms. deposit does not match deposits, so write deposit* or deposit OR deposits when you mean both. act never matches fact.
  • Punctuation inside a word splits it. § 1983 is the phrase section 1983, and rule 10b-5 is the phrase rule 10b 5.
  • A hyphenated word on its own also matches its joined form. non-compete is read as "non compete" OR noncompete, and at-will as "at will" OR atwill.
  • A slash between two words is text, not an operator. and/or is the phrase and or, and 24/7 is 24 7. Anything else containing /, ~ or ^ that is not a known operator is refused, never searched as words.

Precedence

Without parentheses, operators bind in this order, tightest first:
  1. OR (and XOR)
  2. /N and +N
  3. /s and +s
  4. /p and +p
  5. AND
  6. NOT
Within one proximity level, the smaller distance binds first, and at an equal distance the ordered + form binds before the unordered / form. Otherwise operators group left to right. This is the convention of legal research services, not textbook Boolean, where AND binds tighter than OR. parsedQuery parenthesizes every group whose reading could be in doubt, so you can read back exactly how your expression was grouped, and queryWarnings flags AND and OR mixed without parentheses. When in doubt, add parentheses. They never change a correct expression, and parsedQuery drops the ones that are redundant. Each side of a proximity connector (/N, /s, /p and their + forms) must be a term, phrase, wildcard, fuzzy term, an OR group of those, or another proximity expression. AND, NOT and the counting functions cannot sit inside one: (a AND b) /5 c is a 422.

Also accepted

You can paste a search written in another service’s syntax. Each spelling below is read as the operator shown, and parsedQuery echoes the canonical form. A - before a word is NOT, so penalty -6672 excludes 6672 rather than searching for it. A ! before a word is refused: one family of services reads it as NOT and another as a wildcard, so we ask you to write NOT criminal or criminal! instead of guessing.

Negative proximity

NOT /N, NOT /s and NOT /p (and NOT w/N) match a section where the left side occurs at least once outside that range of the right side. landlord NOT /s tenant matches “The landlord sues. The tenant pays.” and does not match “The landlord sues the tenant.” That differs from landlord NOT (landlord /s tenant), which rejects the section the moment any one sentence holds both words.

Refused, never searched as words

A token that looks like an operator is either understood or refused by name. It is never quietly searched as ordinary words, because a misread operator returns a confident, wrong answer. These are refused with a 422:
  • a leading ! (!criminal), a doubled prefix (--x), and a double negation (NOT -x);
  • a placeholder left in a connector (w/n), a connector we do not know (s/5), and any leftover /, ~ or ^ that is not one of the operators above;
  • a distance in sentences or paragraphs (WITH2, SAME3): use /s, /p or /N;
  • regular expressions (/negligen.*/), backslash escapes, number ranges (1..5) and ranges ([2000 TO 2010]);
  • a case-sensitive phrase (^"Internal Revenue"): use the case functions below;
  • title:26, which looks like a U.S. Code title number: use the titleNumber or code filters, or cite( );
  • any field a statute section does not have (see below).
The Errors table lists the exact message for each.

Field restrictions

A term normally searches the section’s body text. Wrap it in a field function to search somewhere else. Write the function name directly before the parenthesis: title (x) is a 422. Fields a statute section does not have are refused by name rather than ignored: dates, judges, courts, parties and the other case-law fields, annotations, credits and history notes, and search-engine fields such as site:. Filter by year with yearFrom and yearTo, by jurisdiction with state, and by code with code or titleNumber. For a section’s amendment history, read GET /us/statutes/section/{actId}/changes.

Case and number functions

Case functions read the text as printed, so allcaps(irs) matches “IRS” and not “Irs”. plural( ) adds a regular plural ending. For an irregular plural, type the plural word itself (children).

Sentences and paragraphs in statute text

/s and /p depend on where a sentence and a paragraph end, and statute text is not prose, so the boundaries are defined for it. They are real boundaries, not fixed word windows. A sentence ends at a sentence-ending period, question mark or exclamation mark followed by a new sentence. Legal abbreviations, decimals and initials do not end one: “Sec.”, “U.S.C.” and “1950.5” stay inside their sentence. A paragraph starts at any of these:
  • a blank line;
  • a subsection marker such as (a), (1), (iv), (A) or (aa) that starts a line, or follows a ., ; or :;
  • a heading line starting Sec., Section, §, Rule or Article.
A single line break is never a paragraph boundary, because much statute text is hard-wrapped mid-sentence. A marker inside a sentence (“under subsection (b) of this section”) does not start a paragraph, and a chained marker such as (2) (a) stays one paragraph rather than leaving the (2) alone. A section with none of these boundaries is one paragraph. So in “(a) The landlord may recover. (b) The tenant shall pay.”, landlord /p tenant does not match: (b) after a period starts a new paragraph.

Wildcards and fuzzy terms

Rules:
  • A wildcard needs at least 3 letters or digits before the first *, !, $ or ?. ab* and *ability are refused. There are no leading wildcards.
  • A length-limited wildcard ($N, or a run of *) allows 1 to 5 extra characters. Use a single * for any number.
  • At most 5 wildcard and fuzzy terms per expression, counting those inside phrases.
  • A fuzzy term allows at most 2 edits (an insertion, deletion or substitution each) and needs at least 3 letters.
  • A wildcard matches letters and digits only. It never crosses a space or punctuation.

Text pasted from Word, PDFs and the web

The expression is normalized before it is read, so a search copied out of a document behaves like one typed by hand:

Response fields

parsedQuery is present only when matchType is boolean. It is your expression in canonical form: aliases replaced by the operators above, implicit phrases quoted, groups parenthesized, redundant parentheses dropped. Sending parsedQuery back as the query runs the same search, so it is the right thing to log, cache or show to a user. queryWarnings is present only when matchType is boolean and the expression is valid but may not mean what you intended. It is a list of plain-English strings, and it never changes the search: the search ran as parsedQuery shows. It flags three cases: The field is omitted when there is nothing to warn about. queryHint is present only when matchType is any and the query looks like a Boolean expression: an uppercase AND, OR or NOT between words, a proximity connector such as /s or /5, or atleastN(, in a query that would parse. It means the search ran as natural language, operators included as ordinary words. Retry with matchType: "boolean" if you meant the operators. A Boolean-looking query is never switched to Boolean mode for you, because the same request must mean the same thing every time. In Boolean mode:
  • noGoodMatch is true only when no section matched, and false otherwise. Every result matches by definition.
  • matchQuality is null. Its tiers are calibrated on natural-language ranking and do not describe membership in a Boolean set.
  • relevanceScore orders the matches, as it does in every mode. Negated terms never contribute to ranking.
  • rankingDegraded: true means the order fell back to a simpler score. Every result still satisfies the expression.

Recall: what you get and what you do not

Boolean mode guarantees precision: every section returned satisfies the expression. It is not an exhaustive enumeration, and three things bound what comes back:
  • At most 120 results per query, as with every search (limit up to 50, offset up to 70). When more than 120 sections match, you get the 120 most relevant. Narrow with state, corpusType, code or titleNumber, or split the expression, to reach the rest.
  • Wildcard and fuzzy terms match the word forms found while searching. retaliat* matches every form that turns up in the candidate sections, which in practice is every common form, but a rare form that appears only in sections the search never reached can be missed. If one form matters, write it out: retaliat* OR retaliatory.
  • Very long sections. When the words of an AND or a proximity pair sit far apart in a long section, that section is still found, but through a relevance-ranked pass, so in a broad expression it can fall outside the 120.
An empty Boolean result means no section in your scope that the search reached satisfies the expression. Before concluding the corpus holds nothing, loosen the expression (/s to /p, /p to AND, a phrase to its words joined by AND) or widen the scope. To count or list every section in a body of law regardless of wording, use POST /us/statutes/count and GET /us/statutes/divisions. See How search works.

Pricing

A Boolean search costs the same as any search: 4 credits per call. A 422 for an expression we cannot read is not charged, because the expression is read before any charge starts, and a 503 from a temporary backend outage is refunded. A valid expression that matches nothing is a completed search and is charged. Read creditsConsumed on the response, and see GET /api-credits/pricing for the live matrix.

Limits

Limits are refused, never truncated: a search that quietly dropped part of your expression would return a different set than the one you asked for.

Coming from another service

A few differences catch people who already write terms-and-connectors searches elsewhere: AND is always written out. Two operands next to a parenthesis with no operator between them, as in landlord tenant (deposit), are a 422 that names the missing operator.

Errors

An expression we cannot read returns 422 with a detail string. It names the problem and, where there is one, the 0-based character position in your query.
A query over 500 characters fails schema validation instead, with the usual loc array described in Errors. If the search backend is temporarily unavailable, the API returns 503 and does not charge. Retry with backoff.

For AI agents

Rules for writing an expression that does what you mean on the first call:
  1. Send matchType: "boolean". Without it the operators are searched as words, and the response carries queryHint.
  2. Write operators in UPPERCASE: AND, OR, NOT, /s, /p, /5. Lowercase and, or, not are words.
  3. Always write AND between concepts. A space makes a phrase: landlord tenant is the phrase “landlord tenant”, not both words.
  4. Quote multi-word terms to make phrases explicit: "security deposit".
  5. Parenthesize every OR group and any mix of operators. Precedence is OR, then /N, /s, /p, then AND, then NOT, which differs from textbook Boolean.
  6. Prefer /s or /p to AND when two ideas must be connected, not merely present in a long section.
  7. Use wildcards for word forms: there is no stemming, so deposit misses deposits. Write deposit*, with at least 3 characters before the *, and no more than 5 wildcard or fuzzy terms.
  8. Exclude with NOT word. Never write !word, which is refused.
  9. Every expression needs one positive term. NOT x alone is refused.
  10. Scope with request fields, not query words. Use state, corpusType, code, titleNumber, yearFrom and yearTo. Field functions exist only for title( ), cite( ) and text( ).
  11. On 422, fix the expression and retry. Read detail: it names the problem and the character position. A 422 costs nothing.
  12. On 503, retry with backoff. It is a temporary backend outage and is not charged; do not change the expression.
  13. Read parsedQuery to confirm the grouping you intended, and log it rather than the raw string. If queryWarnings is present, fix the expression it names before relying on the results.
  14. Treat an empty result as “no match in scope”, not “no such law”. Loosen (/s to /p to AND) or widen the scope before reporting a gap.
  15. To fetch a known citation, do not use Boolean. Call GET /us/statutes/resolve, or search the citation with matchType: "any".
Worked translations from a request to an expression:

How search works

The hybrid ranking model and every matchType.

Search API reference

Every request and response field of POST /us/statutes/search.

Best practices

Scoping, choosing a matchType, and reading the response.

Errors

Status codes and how to recover from each.
Last modified on October 21, 2026