Bindinglaw

REST reference

Nine law endpoints, one envelope.

Base URL https://api.binding.law/v1. Everything is JSON over HTTPS. Successes carry result or results; failures carry error.code and error.message, and the code is what you switch on.

Conventions

POST variants. /law/coverage, /law/lookup, /law/text, /law/search and /law/format also accept POST with the same parameters as a JSON body. The POST path is implemented as a loopback GET, so auth, metering, validation and response shape are identical by construction. Use it when a citation key carries characters you would rather not put in a query string.

The /v1/statutes alias. Every /v1/law/* path is also mounted at /v1/statutes/*, permanently, because earlier integrations hardcoded it. Same handlers, same answers. New code should use /v1/law/*.

Billing. Metered calls bill one unit. Citation resolution bills one unit per citation in the batch. /law/coverage, /law/quality and the health checks bill zero.

Coverage

GET/v1/law/coverageno key

What binding.law carries, for whom, how far back, and how its validity dates should be read. Public and unmetered — call it before spending a lookup, and call it to decide whether a verification is possible at all. Served from a cache refreshed behind the response; when the cached numbers can no longer be trusted as current the payload grows a stale object carrying ageSeconds, refreshFailures and lastError, so a silent refresh failure cannot masquerade as a healthy endpoint.

ParameterMeaning
jurisdictionoptionalstring
Restrict to one jurisdiction code. Omit for all of them.
corpusoptionalstring
Restrict to one corpus. Omit for all of them.
curl "https://api.binding.law/v1/law/coverage?jurisdiction=fl&corpus=statutes"
200 · captured 2026-09-20
{
  "coverage": [
    {
      "jurisdiction": "fl",
      "corpus": "statutes",
      "name": "Florida",
      "cadenceClass": "edition",
      "temporalBasis": "compiled-edition",
      "coverageFrom": "2010-07-01",
      "latestVersion": "2025",
      "sections": 26776,
      "versions": 48076,
      "lastRetrievedAt": "2026-07-22 05:14:30.429+00"
    }
  ],
  "note": "asOf dates earlier than coverageFrom return no_edition_on_file; ...",
  "generatedAt": "2026-09-20T19:51:41.148Z"
}

note is truncated here for width; the live endpoint sends it in full.

  • 500internal_errorThe coverage query failed and no cached value was available.
  • 503statutes_unavailableThe corpus store is not configured on this deployment.

Corpus quality

GET/v1/law/qualityno key

Our own audit of our own data — granularity below section level, bodies missing without a stated disposition, citations whose source URL names a different section. Published deliberately: if you are grounding an agent on this corpus you should be able to see where we say it is thin, rather than discovering it in an answer. Only findings that did not pass are returned. This audits our data, not the law. Public and unmetered.

ParameterMeaning
jurisdictionoptionalstring
Two-letter code. Omit for the latest run across every corpus.
historyoptional"true"
Add history, the last 30 runs, so you can see whether quality is moving.
curl "https://api.binding.law/v1/law/quality?jurisdiction=co&history=true"
200 · captured 2026-09-20
{
  "run": null,
  "findings": [],
  "note": "no audit has been recorded yet"
}

Production has no audit run recorded yet, so this is the live answer today. When a run exists, run carries ranAt, jurisdiction, trigger, totalChecks, passed, warned and failed, and findings carries one object per non-passing check (scope, check_name, status, detail, rows, avg_chars, max_chars, unexplained_empty, misattributed).

  • 503statutes_unavailableThe corpus store is not reachable. This endpoint answers 503 rather than 500 on a query failure.

Lookup a section

GET/v1/law/lookupbearer

One section version — the one in force on asOf — with its full provenance, bitemporal bounds and permalink. Never a nearest guess: if nothing was in force on that date under that key, the answer is a 404 with a code that tells you which kind of nothing it was.

ParameterMeaning
jurisdictionrequiredstring
Lowercase jurisdiction code — us for federal, a two-letter state code, or a circuit code such as us-ca9. Which ones exist is answered by /v1/law/coverage.
citationrequiredstring
The normalized citation key, or the display citation. Matched against both. Key forms differ per jurisdiction and corpus — see Corpora.
corpusoptionalenum
One of statutes (default), regulations, guidance, jury_instructions, rules, guidelines. Anything else is a 400 bad_corpus.
asOfoptionaldate
YYYY-MM-DD. Returns the version in force on that date; defaults to today. Resolved at noon UTC, so date-granular validity ranges do not straddle a midnight boundary. A malformed value is a 400 bad_as_of.
curl -G "https://api.binding.law/v1/law/lookup" \
  -H "Authorization: Bearer $BINDING_API_KEY" \
  --data-urlencode "jurisdiction=fl" \
  --data-urlencode "citation=768.28" \
  --data-urlencode "asOf=2019-03-01"
200 · field set exact, values illustrative
{
  "result": {
    "citation": {
      "jurisdiction": "fl",
      "corpus": "statutes",
      "key": "768.28",
      "display": "§ 768.28, Fla. Stat.",
      "parts": { "title": "XLV", "chapter": "768" }
    },
    "catchline": "Waiver of sovereign immunity in tort actions; ...",
    "bodyText": "... full section text ...",
    "historyNote": "s. 1, ch. 73-313; ...",
    "note": null,
    "status": "active",
    "validFrom": "2019-07-01T00:00:00+00:00",
    "validTo": "2020-07-01T00:00:00+00:00",
    "ingestedAt": "2026-07-22T05:14:30.429+00:00",
    "temporalBasis": "compiled-edition",
    "permalink": "https://binding.law/law/fl/statutes/768.28",
    "provenance": {
      "sourceUrl": "https://www.flsenate.gov/Laws/Statutes/2019/768.28",
      "retrievedAt": "2026-07-22T05:14:30.429+00:00",
      "contentHash": "9f2c...",
      "sourceSystem": "flsenate.gov",
      "versionLabel": "2019"
    },
    "disclaimer": "Unofficial copy of government-published law, ..."
  }
}

Transcribed from the handler that builds it. Every key shown is one the API emits; bodyText, hashes and structure values are abbreviated. Rows in corpus 'rules' that the filing-format registry has read additionally carry topics: ["format"].

  • 400missing_fieldsjurisdiction or citation absent.
  • 400bad_as_ofasOf is not YYYY-MM-DD.
  • 400bad_corpuscorpus is not one of the six.
  • 401missing_bearer · invalid_keyNo token, or an unknown one.
  • 403missing_scopeThe key lacks the lookup scope.
  • 404not_carriedNothing of that corpus for that jurisdiction is held. Stop.
  • 404no_edition_on_fileCarried, but not that key or not on that date. May carry error.didYouMean.
  • 429rate_limited · daily_limit_exceeded · monthly_limit_exceededA ceiling on the key was reached; read Retry-After.
  • 500internal_errorThe query failed.
  • 503statutes_unavailableThe corpus store is not reachable from this deployment.

Section text

GET/v1/law/textbearer

The same resolution as /law/lookup, returning only what you need to quote or compare a quote: citation, catchline, body, history note, our own note, status, temporal basis, version label, permalink and disclaimer. The permalink is included on purpose — an agent quoting a section needs somewhere to send the person who asks where it came from, and for whole-document sources a raw sourceUrl drops them into a multi-megabyte page with no anchor.

ParameterMeaning
jurisdictionrequiredstring
Lowercase jurisdiction code — us for federal, a two-letter state code, or a circuit code such as us-ca9. Which ones exist is answered by /v1/law/coverage.
citationrequiredstring
The normalized citation key, or the display citation. Matched against both. Key forms differ per jurisdiction and corpus — see Corpora.
corpusoptionalenum
One of statutes (default), regulations, guidance, jury_instructions, rules, guidelines. Anything else is a 400 bad_corpus.
asOfoptionaldate
YYYY-MM-DD. Returns the version in force on that date; defaults to today. Resolved at noon UTC, so date-granular validity ranges do not straddle a midnight boundary. A malformed value is a 400 bad_as_of.
200 · field set exact, values illustrative
{
  "result": {
    "citation": { "jurisdiction": "fl", "corpus": "statutes", "key": "768.28", "display": "...", "parts": {} },
    "catchline": "Waiver of sovereign immunity in tort actions; ...",
    "bodyText": "... full section text ...",
    "historyNote": "s. 1, ch. 73-313; ...",
    "note": null,
    "status": "active",
    "temporalBasis": "compiled-edition",
    "versionLabel": "2019",
    "permalink": "https://binding.law/law/fl/statutes/768.28",
    "disclaimer": "Unofficial copy of government-published law, ..."
  }
}

Same parameters, same miss semantics, and the same error codes as /law/lookup.

Court filing formats

GET/v1/law/formatbearer

The filing-format registry: per court, the typeface, minimum type size, line spacing, margins, paper size, length limits and certificate of compliance the rules require — as data, each value quoting the rule text it was read from, each record pinned to the content hash of the rule row it was read from.

A record is a reading of the rules, not the rules. Check stale before relying on one: it is true when a cited rule’s in-force text no longer matches the pin, or when no row is in force, and staleDetail says which. Verify against rules[].citationKey through /v1/law/lookup?corpus= the rule’s rules[].corpus before certifying compliance — rules for a court rule, statuteswhere a statute sets the format (Wisconsin’s appellate courts, keyed statutes:809.81). A court whose carried rules set no statewide typography is still a record, with coverage: "no-statewide-typography-rule", so that “no statewide rule” is an answer rather than a gap.

ParameterMeaning
jurisdictionrequiredstring
Lowercase jurisdiction code; us for federal. Absent is a 400 missing_fields.
leveloptionalenum
One of trial, intermediate-appellate, supreme, specialty. Anything else is a 400 bad_level.
courtoptionalstring
One record by id, formed as <jurisdiction>-<court slug>.
curl -G "https://api.binding.law/v1/law/format" \
  -H "Authorization: Bearer $BINDING_API_KEY" \
  --data-urlencode "jurisdiction=il" \
  --data-urlencode "level=intermediate-appellate"
200 · field set exact, values illustrative
{
  "result": [
    {
      "id": "il-appellate",
      "jurisdiction": "il",
      "court": "Illinois Appellate Court",
      "level": "intermediate-appellate",
      "coverage": "specified",
      "ruleKeys": ["sct-341"],
      "rulePins": { "sct-341": "<contentHash at reading time>" },
      "governingRuleKey": "sct-341",
      "typeface": { "allowed": ["..."], "prohibited": [] },
      "minSizePt": 12,
      "maxSizePt": null,
      "footnoteMinSizePt": null,
      "lineSpacing": "double",
      "margins": { "all": 1.5 },
      "paperSize": "letter",
      "limits": [
        { "document": "brief of appellant", "pages": 50, "basis": "pages", "quote": "..." }
      ],
      "certificateOfCompliance": { "required": true, "ruleKey": "sct-341", "contents": "..." },
      "effectiveFrom": "2020-10-01",
      "basis": { "typeface": "...", "margins": "..." },
      "note": "...",
      "unresolved": ["local rules of the individual districts"],
      "stale": false,
      "staleDetail": null,
      "loadedAt": "2026-09-19T00:00:00+00:00",
      "rules": [
        {
          "key": "sct-341",
          "corpus": "rules",
          "citationKey": "sct-341",
          "display": "Ill. S. Ct. R. 341",
          "effectiveFrom": "2020-10-01",
          "sourceUrl": "https://...",
          "note": null,
          "permalink": "https://binding.law/law/il/rules/sct-341",
          "changedSincePinned": false
        }
      ]
    }
  ],
  "note": "Each record is binding.law's reading of the cited court rules, ...",
  "disclaimer": "Unofficial copy of state statutes served at compiled-edition granularity ..."
}

Records come back highest court first. typeface.allowed is either an exhaustive list of named faces or one of the tokens any, any-conventional, any-proportional, any-serif, court-published-list — and is null where the rules set no typeface requirement. Where a rule's minimum depends on the face, typeface.faceMinimums carries one entry per face and minSizePt alone is not the rule.

  • 400missing_fieldsjurisdiction absent.
  • 400bad_levellevel is not one of the four.
  • 404not_carriedNo record for that jurisdiction; or none matching the level/court filter, in which case the message lists the ids that do exist.
  • 500internal_errorThe lookup failed.
  • 503statutes_unavailableCorpus store unreachable.

Resolve case citations

POST/v1/law/citations/lookupbearer

Resolve case citations to the cases they name, against a local replica of CourtListener’s citation index. Resolution only — whether the case is still good law is not claimed here. The result vocabulary is CourtListener’s own, so a client written against their citation-lookup endpoint needs the base URL changed and results unwrapped.

ParameterMeaning
textoptionalstring
Citations, one per line, up to 64,000 characters and 250 citations. One of text or citations is required.
citationsoptionalstring[]
The same thing as an array. Joined with newlines internally.
fallbackoptionalenum
none (default) or courtlistener. With courtlistener, misses go upstream in one request, hits replace them tagged source: "courtlistener", and the clusters learned are written into the replica. The request never fails because the fallback did — read fallback.status.
curl -X POST "https://api.binding.law/v1/law/citations/lookup" \
  -H "Authorization: Bearer $BINDING_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"text": "347 U.S. 483\n999 F.3d 1", "fallback": "courtlistener"}'
200 · field set exact, values illustrative
{
  "results": [
    {
      "citation": "347 U.S. 483",
      "normalized_citations": ["347 U.S. 483"],
      "start_index": 0,
      "end_index": 12,
      "status": 200,
      "error_message": "",
      "clusters": [
        {
          "id": 105221,
          "absolute_url": "/opinion/105221/brown-v-board-of-education/",
          "courtlistener_url": "https://www.courtlistener.com/opinion/105221/brown-v-board-of-education/",
          "case_name": "Brown v. Board of Education",
          "case_name_full": "...",
          "case_name_short": "...",
          "date_filed": "1954-05-17",
          "court": "scotus",
          "docket_id": null,
          "docket": null,
          "precedential_status": "Published",
          "citation_count": 0,
          "citations": [{ "volume": "347", "reporter": "U.S.", "page": "483", "type": 1 }]
        }
      ]
    }
  ],
  "provenance": {
    "source": "courtlistener-bulk",
    "dataAsOf": "2026-09-11",
    "resolution": "volume/reporter/page against search_citation"
  },
  "fallback": { "attempted": 0, "resolved": 0, "capped": 0, "backfilled": 0, "status": "none" },
  "disclaimer": "..."
}

status uses CourtListener's vocabulary: 200 found, 300 ambiguous (up to eight candidates), 404 not found, 400 unknown reporter. The fallback object is present only when you asked for one; its status is one of ok, unavailable, rate_limited, skipped, none. The response also carries an x-binding-fallback-remaining header with CourtListener's remaining daily requests on the shared token.

  • 400missing_fieldsBody is neither { text } nor { citations }.
  • 400bad_fallbackfallback is not "none" or "courtlistener".
  • 400too_manyMore than 250 citations parsed; batch the request.
  • 413too_largetext exceeds 64,000 characters.
  • 500internal_errorThe resolution query failed.
  • 503caselaw_unavailableThe case-law replica is not configured on this deployment.

A case, and what cites it

GET/v1/law/cases/{clusterId}bearer

One case (a CourtListener cluster) with its parallel citations, court, filing date and cited_by_count, the number of distinct cases that cite it. clusterId must be a positive integer; anything else is a 400 bad_id, and an unknown id is a 404 not_found.

GET/v1/law/cases/{clusterId}/citingbearer

The cases that cite this one, most-cited first, from CourtListener’s citation graph. Each result carries depth, how many times the citing opinion cites this one. Treatment — followed, distinguished, overruled — is deliberately absent: it needs a classifier over opinion text, and a citing list mistaken for a good-law signal is worse than none.

ParameterMeaning
limitoptionalinteger
1 to 100, default 50. Clamped, not rejected.
offsetoptionalinteger
Zero or greater, default 0. The envelope echoes total, limit and offset.
  • 400bad_idclusterId is not a positive integer.
  • 404not_foundNo cluster with that id. (/cases/{id} only.)
  • 500internal_errorThe query failed.
  • 503caselaw_unavailableReplica not configured.

Health and the spec

GET/v1/healthno key

Is the process alive. Never touches the corpus, answers in microseconds, and is what the load balancer polls. It stays green through a corpus outage — correctly, because the process is fine. Do not point uptime monitoring at it.

GET/v1/health/corpusno key

Can law actually be served. This one touches the corpus and answers 503 when it is unreachable, which is precisely the condition /v1/law/coverage hides by design when it falls back to its cache. This is the endpoint to monitor. The underlying probe runs at most every five minutes however often you call it, and checkedSecondsAgo tells you how old the verdict is; a verdict older than fifteen minutes is reported as 503 unknown / no_recent_probe rather than passed off as healthy.

200 · captured 2026-09-20
{
  "ok": true,
  "status": "healthy",
  "reason": "ok",
  "checkedSecondsAgo": 41,
  "service": "lawfirm.dev/v1",
  "timestamp": "2026-09-20T19:53:48.552Z"
}
GET/v1/openapi.yamlno key

The machine-readable spec, also served as /v1/openapi.json. Where it and this page disagree, the handlers are the truth and we would like to know.

Bindinglaw

Point-in-time US law with the receipt attached. Source URL, retrieval time, content hash, and validity dates on every answer.

curl api.binding.law/v1/law/coverage

© 2026 binding.law · a Jubal, Inc. productAttorneys and firms never pay. Ever.