Bindinglaw

Errors

Every code, and what it wants you to do.

One envelope everywhere: { "error": { "code", "message" } }. The code is stable and safe to switch on; the message is written for a person reading a response and may change. Two of these codes are not failures at all.

not_carried is not no_edition_on_file

This is the distinction to get right, and it is the reason we never answer a miss with a nearest guess. Both are 404. They mean opposite things, and an agent that conflates them will go and cite something wrong.

It is not hypothetical. A jubal.law agent asked for a Florida court rule. We carried no state court rules at the time, but the answer came back as no_edition_on_file with a message written for Florida statutes. The agent read “we have this material, just not that number”, went to the open web, and cited a superseded rule.

not_carried — stop

We hold nothing of that material for that jurisdiction. No citation within it can be confirmed or denied by us, and nothing you find elsewhere carries our authority. The correct behaviour is to tell the user the source is not carried — not to search somewhere else and present the result as though it came from here. /v1/law/coverage lists what is carried.

404 · not_carried
{
  "error": {
    "code": "not_carried",
    "message": "binding.law does not carry FL rules. This is a stated gap, not a lookup failure: nothing of that material for that jurisdiction is in the corpus, so no citation within it can be confirmed or denied, and nothing found elsewhere on the open web carries binding.law's authority. See /v1/law/coverage for what is carried."
  }
}

no_edition_on_file — look again

We carry that material. This particular key is not on file, or nothing under it was in force on the date you asked for. Three things to check: the form of the key, the asOf date against that jurisdiction’s coverageFrom, and error.didYouMean when it is present.

404 · no_edition_on_file
{
  "error": {
    "code": "no_edition_on_file",
    "message": "binding.law carries FL statutes, but has no section matching 768.99 on file for 2026-09-20. We never resolve to a nearest edition. Coverage begins at the date reported for FL statutes in /v1/law/coverage; a citation outside that window, or a key in a different form, both land here."
  }
}

When the number you asked for exists under a fuller key, the miss names the candidates rather than picking one. Florida’s 401.14 is a different instruction in the civil set and in the contract and business set; guessing one would be worse than offering both.

404 · no_edition_on_file with didYouMean
{
  "error": {
    "code": "no_edition_on_file",
    "message": "No FL jury instructions is keyed exactly \"401.14\", but these keys match it: civil-401.14, contract-401.14. Retry with one of them — they are different instruments, so pick by publication rather than assuming the first. Nothing has been guessed on your behalf.",
    "didYouMean": [
      { "citationKey": "civil-401.14", "citationDisplay": "Fla. Std. Jury Instr. (Civ.) 401.14" },
      { "citationKey": "contract-401.14", "citationDisplay": "Fla. Std. Jury Instr. (Contract & Bus.) 401.14" }
    ]
  }
}

Illustrative keys. The didYouMean array carries up to five candidates, each with its citationKey and its citationDisplay, and appears only when a suffix match was found within the carried material.

On MCP, a not_carried body additionally carries a note field merged into the JSON, repeating the instruction in the form a model will act on. See the MCP page.

The full list

Authentication and limits

missing_bearerHTTP 401

No Authorization header, or one whose token after Bearer is empty.

Send Authorization: Bearer <key>. Coverage, quality and health need no key at all.

invalid_keyHTTP 401

The key did not match an active record. Revoked keys answer identically.

Check the key was copied whole, and that it has not been revoked. Keys are shown once; reissue rather than hunt.

missing_scopeHTTP 403

The key is valid but lacks the scope the endpoint requires. Every law endpoint requires lookup.

Issue a key with the lookup scope. The message names the scope it wanted.

rate_limitedHTTP 429

The key's per-minute request ceiling. A coarse 120/minute edge limit can also produce this.

Honour Retry-After, which is 60. Spread the burst.

daily_limit_exceededHTTP 429

The key's daily billable-unit cap. Windows are UTC.

Retry-After carries the seconds until 00:00 UTC — use it rather than retrying every minute.

monthly_limit_exceededHTTP 429

The key's monthly billable-unit cap.

Retry-After carries the seconds until the 1st. Raise the plan or the cap.

Request validation

missing_fieldsHTTP 400

A required parameter is absent: jurisdiction or citation on lookup and text; q on search; jurisdiction on format; a usable body on citation lookup.

The message names what was wanted. On MCP, citation can also arrive under its alias key.

bad_as_ofHTTP 400

asOf is not YYYY-MM-DD.

Send a plain date. There is no time component; it is resolved at noon UTC internally.

bad_corpusHTTP 400

corpus is not one of statutes, regulations, guidance, jury_instructions, rules, guidelines.

Use one of the six. The list is closed and the message repeats it.

bad_levelHTTP 400

level on /law/format is not one of trial, intermediate-appellate, supreme, specialty.

Use one of the four, or drop the filter and read level off each record.

bad_fallbackHTTP 400

fallback on citation lookup is not "none" or "courtlistener".

Omit it for none.

bad_idHTTP 400

clusterId in a /law/cases path is not a positive integer.

Cluster ids are integers. Pull one from a citation-lookup result's clusters[].id.

too_manyHTTP 400

More than 250 citations were parsed out of a citation-lookup body.

Batch the request.

too_largeHTTP 413

text on citation lookup exceeds 64,000 characters.

Split the document. The limit matches CourtListener's own.

Misses

not_carriedHTTP 404

binding.law holds nothing of that material for that jurisdiction. Also returned by /law/format when no record exists, and by /law/search when a single named jurisdiction holds nothing of that corpus.

Stop. Do not look elsewhere on binding.law's authority. Say the source is not carried, and check /v1/law/coverage for what is.

no_edition_on_fileHTTP 404

The material is carried, but nothing matches that citation key, or nothing was in force on that date.

Read error.didYouMean if present, check the key's form, and check asOf against that jurisdiction's coverageFrom.

not_foundHTTP 404

No case cluster with that id. Case-law only.

Resolve a citation first and use the cluster id it returns.

Server and dependency

internal_errorHTTP 500

The query failed. The message names which operation — lookup, search, format, citation lookup.

Retry once. If it persists, check /v1/health/corpus and tell us.

statutes_unavailableHTTP 503

The law corpus store is not configured or not reachable from this deployment.

Retry with backoff. /v1/health/corpus answers the same question directly and is the endpoint to monitor.

caselaw_unavailableHTTP 503

The case-law replica is not configured on this deployment.

Retry with backoff. Law endpoints are unaffected — the two stores are separate.

MCP transport errors

The MCP endpoint answers in JSON-RPC rather than the HTTP error envelope. Two codes:

-32001HTTP 401
The POST carried no Authorization: Bearer header.
-32000HTTP 405
A GET or DELETE was attempted. The server is stateless, so session operations do not exist. POST only.

Everything else — a 404 miss, a 400, a 429 — arrives as an ordinary tool result carrying the REST error body, because an explicit miss is information rather than a transport failure.

Two signals that are not errors

stale on a coverage response. Coverage is served from a cache refreshed behind the response. Past an hour without a successful refresh the payload grows a stale object with ageSeconds, refreshFailures and lastError. The status is still 200 — a stale count beats an outage for a public matrix — but the numbers are labelled so a silent refresh failure cannot look healthy. It exists because a rotated database password once let coverage serve pre-rotation totals for ten hours while ingests were landing.

stale: true on a filing-format record. A record is our reading of the rules, pinned to the content hash of the rule row it was read from. stale is true when a cited rule’s in-force text no longer matches that pin, or when no row is in force; staleDetail says which rule and which way. Do not certify a filing against a stale record — re-read the rule through /v1/law/lookup?corpus=rules.

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.