{"openapi":"3.1.0","info":{"title":"LitLex API","version":"v1","description":"Retrieval API over the LitLex corpus: 2.55M federal opinions, 28M+ paragraph-anchored text units, 18.4M citation edges, an AI citator, and USC/CFR text. Built for research agents: every piece of opinion text carries a pre-formatted pinpoint anchor (`short_id::p.N`) so you cite pinpoints you did not invent, and every quote you plan to rely on can be byte-verified with /v1/cite-check before it leaves your draft. Where star pagination is on file, paragraphs and cite-check matches also carry `reporter_pincite` — a true Bluebook page pinpoint (\"550 U.S. 544, 579\") to cite verbatim; when absent, the reporter page is not derivable here — do not invent one.\n\nTypical workflow: (1) /v1/search for propositions, or /v1/cite/resolve for citations you already hold; (2) /v1/opinions/{id} to read paragraphs; (3) /v1/opinions/{id}/citator to confirm the case is still good law and /v1/opinions/{id}/authorities to walk what it relies on; (4) /v1/cite-check (or /batch) to verify every quote before delivering work.\n\nAuth: `Authorization: Bearer llx_…` on every endpoint except /v1/health and /v1/openapi.json. Rate limiting: token bucket per key (default 5 rps, burst 2×; per-key overrides exist) — 429 `rate_limited`. Monthly unit caps per key — 429 `quota_exceeded`. Every response is enveloped: `{data, meta?}` on success, `{error: {code, message, details?}}` on failure; error codes are stable API surface. Treatments and headnotes are AI-generated (not editorial) and say so in-band.\n\nPricing (rate card, also machine-readable in `x-litlex-rate-card`): usage is metered in weighted units — search 3, citator 2, authorities 2, cite-check 2 (batch: 2 per item), opinion read 1, cite resolve 1, statute 1; health and this document are free. Developer tiers: Free eval $0/mo, 500 units included, HARD CAP (no overage — 429 with an upgrade message); Starter $49/mo, 25,000 units included, overage $2.50 per 1,000; Growth $299/mo, 250,000 included, overage $1.50/1,000; Scale $999/mo, 1,000,000 included, overage $1.00/1,000. Paid tiers never refuse on included units — overage bills automatically; an absolute monthly abuse cap (default 10× included) still applies. LitKit research seats pool 10,000 units/seat/month firm-wide, with overage at the Growth rate. No tier is flat-unlimited. Terms: no bulk export of the corpus and no redistribution/resale of corpus content as a dataset (docs/API_PRODUCT_SPEC_2026-07-12.md §9 and §13)."},"x-litlex-rate-card":{"unit_weights":{"POST /v1/search":3,"GET /v1/opinions/:id/citator":2,"GET /v1/opinions/:id/authorities":2,"POST /v1/cite-check":2,"POST /v1/cite-check/batch":2,"GET /v1/opinions/:id":1,"GET /v1/cite/resolve":1,"GET /v1/statutes/:cite":1,"GET /v1/health":0,"GET /v1/openapi.json":0,"mcp:search":3,"mcp:citator":2,"mcp:get_authorities":2,"mcp:cite_check":2,"mcp:get_opinion":1,"mcp:resolve_citation":1,"mcp:statute":1},"cite_check_batch":"2 units per submitted item","tiers":{"free_eval":{"monthly_usd":0,"included_units":500,"overage_usd_per_1k":null,"hard_cap":true},"starter":{"monthly_usd":49,"included_units":25000,"overage_usd_per_1k":2.5,"hard_cap":false},"growth":{"monthly_usd":299,"included_units":250000,"overage_usd_per_1k":1.5,"hard_cap":false},"scale":{"monthly_usd":999,"included_units":1000000,"overage_usd_per_1k":1,"hard_cap":false},"seat_allowance":{"monthly_usd":0,"included_units":0,"overage_usd_per_1k":1.5,"hard_cap":false},"internal":{"monthly_usd":0,"included_units":1000000000,"overage_usd_per_1k":null,"hard_cap":true}},"seat_allowance_note":"seat_allowance keys draw on a firm-level pool of active entitled seats × 10,000 units/month; overage bills at the Growth rate.","terms":"No bulk export; no redistribution or resale of corpus content as a dataset. See the API product terms."},"servers":[{"url":"/","description":"Same host the document was fetched from."}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"llx_<40 hex chars>","description":"LitLex API key. Keys are sha256-hashed at rest; a lost plaintext cannot be recovered — mint a new key."}},"schemas":{"ErrorEnvelope":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","key_disabled","rate_limited","quota_exceeded","invalid_request","not_found","ambiguous_short_id","not_configured","upstream_unavailable","internal"],"description":"Stable machine-readable code. Transport/DB failures are 5xx codes, never not_found — a network error never reads as \"no such case\"."},"message":{"type":"string"},"details":{"description":"Optional structured context: zod issues on invalid_request, candidate opinions on ambiguous_short_id."}}}}},"OpinionMeta":{"type":"object","required":["opinion_id","short_id","case_name","court","paragraph_count","text_caveats"],"properties":{"opinion_id":{"type":"string","format":"uuid"},"short_id":{"type":"string"},"case_name":{"type":"string"},"court":{"type":"string","description":"CourtListener court id (e.g. scotus, ca9)."},"decided_date":{"type":["string","null"],"description":"YYYY-MM-DD."},"reporter_cite":{"type":["string","null"]},"author":{"type":["string","null"]},"disposition":{"type":["string","null"]},"paragraph_count":{"type":"integer"},"text_caveats":{"type":"array","items":{"type":"string","enum":["syllabus_inline"]},"description":"Known text-provenance hazards, empty when none. syllabus_inline: the text may open with the Reporter's syllabus as its first paragraphs — never quote the syllabus as the Court's opinion."}}},"Paragraph":{"type":"object","required":["n","text","anchor"],"properties":{"n":{"type":"integer","description":"Paragraph number within the opinion."},"text":{"type":"string"},"anchor":{"type":"string","description":"Pre-formatted pinpoint anchor `short_id::p.N`. Cite THIS, verbatim — it removes the invented-pinpoint hallucination path."},"reporter_page":{"$ref":"#/components/schemas/ReporterPage"},"reporter_pincite":{"type":"string","description":"Pre-formatted Bluebook-style pincite for this paragraph (\"550 U.S. 544, 579\") when star pagination is on file — cite it verbatim."}}},"ReporterPage":{"type":"object","required":["reporter","volume","page_start","page_end"],"description":"Official reporter page span (star pagination) — the source of true Bluebook page pinpoints. Present only when page anchors are on file for the opinion (coverage is partial); absence means the page number is not derivable here — do not guess one.","properties":{"reporter":{"type":"string","description":"e.g. \"U.S.\", \"F.3d\"."},"volume":{"type":"integer"},"page_start":{"type":"integer","description":"Reporter page at the start of the paragraph."},"page_end":{"type":"integer","description":"Reporter page at the end of the paragraph."}}},"CiteMatch":{"type":"object","required":["opinion_id","short_id","case_name","court","cite","matched_via"],"properties":{"opinion_id":{"type":"string","format":"uuid"},"short_id":{"type":"string"},"case_name":{"type":"string"},"court":{"type":"string"},"decided_date":{"type":["string","null"]},"cite":{"type":"string","description":"The cite form that matched, readable."},"matched_via":{"type":"string","enum":["reporter_fields","citations_table"],"description":"reporter_fields = the opinion row carries this cite; citations_table = resolved through parallel citations other opinions used."},"paragraph_count":{"type":"integer","description":"Present on reporter_fields matches. The corpus holds duplicate rows per case (bulk source + one row per opinion document); bigger = fuller text. Matches are ordered best-first."}}},"CiteCheckResult":{"type":"object","required":["verdict"],"properties":{"verdict":{"type":"string","enum":["verified_exact","verified_fuzzy","not_found","not_checked"]},"match":{"type":"object","properties":{"anchor":{"type":"string"},"opinion_id":{"type":"string"},"short_id":{"type":"string"},"case_name":{"type":"string"},"paragraph_number":{"type":"integer"},"similarity":{"type":"number","description":"Fuzzy pass only, 0..1."},"matched_text":{"type":"string","description":"The corpus paragraph that matched."},"diff":{"type":"string","description":"Fuzzy pass only: word-level diff, -quoteWord +corpusWord."},"reporter_page":{"$ref":"#/components/schemas/ReporterPage"},"reporter_pincite":{"type":"string","description":"Pre-formatted Bluebook-style pincite for the matched paragraph (\"550 U.S. 544, 579\") when star pagination is on file — cite it verbatim."}}},"pinpoint_correct":{"type":"boolean","description":"Present when the request claimed a paragraph_number."},"reason":{"type":"string","description":"Present on not_checked / some not_found."}}},"AuthorityItem":{"type":"object","required":["cited_opinion","resolved","citation_count","paragraph_count"],"properties":{"cited_opinion":{"type":"object","required":["cite_string"],"properties":{"opinion_id":{"type":"string","format":"uuid","description":"Absent when resolved=false."},"short_id":{"type":"string"},"case_name":{"type":"string"},"reporter_cite":{"type":["string","null"]},"cite_string":{"type":["string","null"],"description":"Raw cite string as extracted from the citing text."}}},"resolved":{"type":"boolean","description":"false = the cited authority is outside the corpus (state reporters, statutes, secondary sources); the raw cite string still tells you what the case relies on."},"citation_count":{"type":"integer","description":"Occurrences in the citing opinion."},"paragraph_count":{"type":"integer","description":"Distinct citing paragraphs (0 when paragraph links are absent)."},"first_citing_paragraph":{"type":["integer","null"],"description":"First paragraph of the CITING opinion where the cite occurs — fetch it via /v1/opinions/{id}?paragraphs=N to read the citing context."},"treatment":{"type":"object","description":"How THIS opinion treats the authority, when the AI classifier scored the pair (e.g. followed, distinguished, overruled). AI-classified — confidence rides along.","properties":{"treatment":{"type":"string"},"confidence":{"type":["number","null"]}}}}}}},"paths":{"/v1/health":{"get":{"security":[],"summary":"Liveness + dependency status (no auth).","description":"Check before a long research session: reports DB reachability, whether the embedding endpoint is configured (vector search channel), and whether FTS is on.","responses":{"200":{"description":"Service status.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"status":{"type":"string","enum":["ok","degraded"]},"db":{"type":"string","enum":["ok","unreachable"]},"embed_configured":{"type":"boolean"},"fts":{"type":"boolean"},"version":{"type":"string"}}}}}}}}}}},"/v1/openapi.json":{"get":{"security":[],"summary":"This document (no auth).","responses":{"200":{"description":"OpenAPI 3.1 document."}}}},"/v1/search":{"post":{"summary":"Hybrid search (vector + FTS, RRF-fused) over 2.55M federal opinions.","description":"The entry point when you have a proposition, doctrine, or fact pattern but no citation. Returns paragraph-level hits, each with the anchor to cite, a snippet, and a treatment-status chip (negative|caution|positive-context|none) so you can avoid building on bad law. Case-NAME lookups go here too (query the name); citation strings go to /v1/cite/resolve instead. Follow up with /v1/opinions/{id} to read full context and /v1/opinions/{id}/citator before relying on a case.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","minLength":2,"maxLength":2000},"top_k":{"type":"integer","minimum":1,"maximum":25,"default":10},"filters":{"type":"object","properties":{"courts":{"type":"array","items":{"type":"string"},"maxItems":30,"description":"CourtListener court ids (scotus, ca9, nysd…)."},"decided_after":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"decided_before":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"judge":{"type":"string","description":"Substring match on author."},"reporter":{"type":"string","description":"e.g. f3d, F.3d (normalized)."},"treatment_status":{"type":"string","enum":["any","clean","negative","overruled"]}}}}}}}},"responses":{"200":{"description":"Ranked hits.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"hits":{"type":"array","items":{"type":"object","required":["anchor","opinion_id","short_id","paragraph_number","snippet","score"],"properties":{"anchor":{"type":"string","description":"Pinpoint anchor `short_id::p.N` — cite this verbatim."},"opinion_id":{"type":"string"},"short_id":{"type":"string"},"paragraph_number":{"type":"integer"},"case_name":{"type":"string"},"court":{"type":"string"},"decided_date":{"type":["string","null"]},"reporter_cite":{"type":["string","null"]},"author":{"type":["string","null"]},"snippet":{"type":"string"},"score":{"type":"number"},"treatment_status":{"type":"string","enum":["negative","caution","positive-context","none"]}}}}}},"meta":{"type":"object","properties":{"channels":{"type":"object","properties":{"vector":{"type":"boolean"},"fts":{"type":"boolean"}}},"total_candidates":{"type":"integer"},"degraded":{"type":"object","description":"Present only when a search channel failed at runtime and the search degraded to the surviving channel (e.g. embed outage or a vector-query statement timeout → FTS-only). Keys name the failed channel; values say why. Absent when every configured channel ran. Both channels failing is an error, not a degraded 200.","properties":{"vector":{"type":"string","enum":["embedding_unavailable","statement_timeout","query_failed"]},"fts":{"type":"string","enum":["embedding_unavailable","statement_timeout","query_failed"]}}},"hint":{"type":"string","description":"Recovery guidance, present only on an empty full-text-only result: FTS requires every significant term to match, so long doctrinal queries over-constrain it — retry with a shorter query of the most distinctive terms."}}}}}}}},"400":{"description":"Invalid request (zod issues in details).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"503":{"description":"No channel could serve the search (embedding endpoint down or corpus query timed out, with no fallback channel).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cite/resolve":{"get":{"summary":"Resolve a case citation string into opinion id(s).","description":"Use when you already HOLD a citation ('561 U.S. 89', '650 B.R. 803', optional pinpoint '561 U.S. 89, 94') and need the opinion to read or verify — resolve, then fetch /v1/opinions/{id}. Cite-only by design: case names and docket numbers go through /v1/search. Statute cites ('17 U.S.C. § 107') are rejected with a pointer to /v1/statutes/{cite}. Resolution order: exact match on the opinion's own reporter/volume/page, then the corpus citation graph for parallel cites. Multiple matches are REAL (parallel reporters, duplicate source rows) — all are returned best-first; prefer the first, or the one with the highest paragraph_count when you want the fullest text.","parameters":[{"name":"cite","in":"query","required":true,"schema":{"type":"string","minLength":3,"maxLength":120},"description":"e.g. `561 U.S. 89`, `123 F. Supp. 2d 456`, `561 U.S. 89, 94` (pinpoint)."}],"responses":{"200":{"description":"Matches, best-first.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["cite","matches"],"properties":{"cite":{"type":"string","description":"Normalized readable form of the parsed cite."},"pinpoint_page":{"type":"integer","description":"Echoed back when the input carried a pinpoint page."},"matches":{"type":"array","items":{"$ref":"#/components/schemas/CiteMatch"}}}}}}}}},"400":{"description":"Unparseable as a case cite, or a statute cite (use /v1/statutes).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Parsed fine but no opinion in the corpus carries it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/opinions/{id}":{"get":{"summary":"Opinion text, paragraph-anchored.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Opinion uuid or short_id (from search/citator/resolve results)."},{"name":"paragraphs","in":"query","required":false,"schema":{"type":"string","pattern":"^(\\d+(-\\d+)?)(,\\d+(-\\d+)?)*$"},"description":"Range `12-30` (span ≤60) or list `1,4,9` (≤40); omit for the full opinion."}],"description":"The reading surface. Quote ONLY from `paragraphs[].text` and cite the provided `anchor` — never quote `headnotes` (AI-generated summaries; the payload marks them headnotes_generated: \"ai\") and never quote syllabus paragraphs when opinion.text_caveats contains \"syllabus_inline\". When `truncated` is true, page on from `next_paragraph`. 409 on an ambiguous short_id — retry with the uuid from details.candidates.","responses":{"200":{"description":"Opinion text + metadata.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["opinion","paragraphs","truncated","render_source"],"properties":{"opinion":{"$ref":"#/components/schemas/OpinionMeta"},"paragraphs":{"type":"array","items":{"$ref":"#/components/schemas/Paragraph"}},"headnotes":{"type":"array","items":{"type":"object","properties":{"n":{"type":"integer"},"text":{"type":"string"},"topics":{"type":"array","items":{"type":"string"}}}}},"headnotes_generated":{"type":"string","enum":["ai"],"description":"Present whenever headnotes are: they are AI-generated, not editorial."},"headnotes_note":{"type":"string"},"text_caveats_note":{"type":"string","description":"Present when opinion.text_caveats is non-empty."},"truncated":{"type":"boolean"},"next_paragraph":{"type":"integer"},"render_source":{"type":"string","enum":["paragraphs","fulltext_fallback"]}}}}}}}},"400":{"description":"Bad paragraphs parameter.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No such opinion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Ambiguous short_id — candidates in details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/opinions/{id}/citator":{"get":{"summary":"Is this case still good law? Treatment rollup + citing opinions.","description":"Run before relying on any case. Returns a good-law verdict (likely_yes | uncertain | no), verified overruling records (authority_status: the overruling court/case/cite with the supporting quote — the ONLY source of a 'no' verdict besides audited overrules_direct edges; raw AI kill labels alone cap at 'uncertain'), treatment counts, and the citing opinions WITH the paragraphs where the citation occurs (anchored into the citing opinion) so treating language can be quoted honestly. Treatments are AI-classified with audited corrections overlaid: named negative rows under 0.6 confidence are suppressed into counts. Filter with ?treatment=overrules_direct to see verified kill shots first.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"treatment","in":"query","required":false,"schema":{"type":"string","maxLength":40}},{"name":"max_citing","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"default":10}}],"responses":{"200":{"description":"Citator report.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"cited":{"type":"object"},"verdict":{"type":"string","enum":["likely_yes","uncertain","no"]},"verdict_confidence":{"type":"number"},"authority_status":{"type":"array","description":"Verified overruling records for this case (empty = none on file). Each carries the true overruling authority and the quote evidencing it.","items":{"type":"object","properties":{"status":{"type":"string","enum":["overruled","superseded_by_statute"]},"overruled_by_court":{"type":["string","null"]},"overruled_by_case_name":{"type":["string","null"]},"overruled_by_cite":{"type":["string","null"]},"supporting_quote":{"type":"string"},"confidence":{"type":["number","null"]}}}},"treatment_counts":{"type":"array","items":{"type":"object"}},"low_confidence_suppressed":{"type":"integer"},"citing":{"type":"array","items":{"type":"object"}}}}}}}}},"400":{"description":"Bad parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No such opinion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Ambiguous short_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/opinions/{id}/authorities":{"get":{"summary":"Table of authorities: everything this opinion cites.","description":"The outbound half of the citation graph (citator = inbound). Use it to walk a case's foundations: each cited authority comes with occurrence counts, the first citing paragraph (fetch /v1/opinions/{id}?paragraphs=N to read the citing context), and — when classified — how THIS case treats that authority (followed/distinguished/overruled…). Authorities outside the corpus still appear with resolved:false and their raw cite string, so you know what the case relies on even when the text is not here; resolve promising raw cites via /v1/cite/resolve or read them elsewhere.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Authorities, most-cited first.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["citing","authorities"],"properties":{"citing":{"type":"object","properties":{"opinion_id":{"type":"string"},"short_id":{"type":"string"},"case_name":{"type":"string"}}},"authorities":{"type":"array","items":{"$ref":"#/components/schemas/AuthorityItem"}},"note":{"type":"string","description":"Present when total is 0: zero outbound edges nearly always means the citation graph is not yet populated for this opinion (parts of the corpus are mid-repair), NOT that the opinion cites no authority. Reconstruct the table of authorities from the opinion text instead."}}},"meta":{"type":"object","properties":{"total":{"type":"integer","description":"Total distinct authorities."},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"400":{"description":"Bad pagination parameters.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"No such opinion.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"409":{"description":"Ambiguous short_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/statutes/{cite}":{"get":{"summary":"USC / CFR text by citation (latest loaded version).","description":"Statutory and regulatory text: '17 U.S.C. § 107', '17 usc 107(a)', '17 cfr 240.10b-5', '17 usc ch. 1'. URL-encode the cite. Returns the unit (status column flags repealed/reserved/renumbered — check it before relying) plus one level of children, so a section arrives with its subsections in one call.","parameters":[{"name":"cite","in":"path","required":true,"schema":{"type":"string"},"description":"URL-encoded, forgiving format."}],"responses":{"200":{"description":"Statute unit + children.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"unit":{"type":"object"},"children":{"type":"array","items":{"type":"object"}}}}}}}}},"400":{"description":"Unparseable statute cite.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"404":{"description":"Parsed but no such unit loaded.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cite-check":{"post":{"summary":"Verify one quote against corpus bytes.","description":"Run on EVERY quote before it leaves your draft. Scoped mode (opinion_id given — strongly preferred): exact normalized match, then fuzzy (pg_trgm) with a word-level diff showing exactly what drifted. Corpus-wide mode (no opinion_id) finds the source of an unattributed quote; requires server-side FTS, otherwise refuses as not_checked (it never guesses). verified_exact means the bytes are in the corpus paragraph in `match` — cite its anchor. not_found after a real search means the quote is not in that opinion: fix or drop it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quote"],"properties":{"quote":{"type":"string","minLength":15,"maxLength":2000},"opinion_id":{"type":"string","description":"uuid or short_id — scope when you can."},"paragraph_number":{"type":"integer","minimum":1,"description":"Claimed pinpoint; response says whether it was correct."}}}}}},"responses":{"200":{"description":"Verification verdict.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CiteCheckResult"}}}}}},"400":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}},"/v1/cite-check/batch":{"post":{"summary":"Verify up to 50 quotes in one call (results in order).","description":"The pre-delivery sweep: collect every quote in a draft and verify them in one request. Items may scope by opinion_id OR by a case cite string (resolved through /v1/cite/resolve internally; the chosen opinion id is echoed as resolved_opinion_id) OR neither (corpus-wide, FTS required). One bad item never fails the batch — each slot carries either `result` or `error` (invalid_cite, cite_not_resolved, item_timeout, item_failed). Each item runs under its own statement + wall-clock timeout. METERING: a batch call spends one usage unit PER ITEM, not per call.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["quote"],"properties":{"quote":{"type":"string","minLength":15,"maxLength":2000},"opinion_id":{"type":"string"},"cite":{"type":"string","description":"Case cite ('561 U.S. 89') used when opinion_id is absent."},"paragraph_number":{"type":"integer","minimum":1}}}}}}}}},"responses":{"200":{"description":"Per-item outcomes, in submission order.","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"type":"object","required":["index"],"properties":{"index":{"type":"integer"},"result":{"allOf":[{"$ref":"#/components/schemas/CiteCheckResult"},{"type":"object","properties":{"resolved_opinion_id":{"type":"string","description":"Present when the item scoped via `cite`."}}}]},"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"meta":{"type":"object","properties":{"units":{"type":"integer","description":"Usage units this call spent (= item count)."}}}}}}}},"400":{"description":"Invalid request (bad items array).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"401":{"description":"Missing/invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"403":{"description":"Key disabled (revoked).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"429":{"description":"Rate limited (token bucket per key, burst 2×rate) or monthly quota exhausted — check error.code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"500":{"description":"Internal error. Never means not-found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}}}}}}}