DocumentationBrowse
Citation verification
Every reporter citation in the answer is checked against a real index before you see it. A citation that affirmatively does not exist gets the answer rewritten once, and the rewrite is checked again.
The design is deliberately asymmetric. Telling a lawyer that a real case is fake is worse than saying nothing, so the system only reports a fabrication when it has positive evidence of absence, and reports everything else as an absence of signal.
The four statuses
Every checked citation lands in exactly one of these.
| Status | What it means | What your interface should do |
|---|---|---|
| found | The citation resolves to a real reported decision in the DocketRouter library: the Texas law index or the citation table. Where the library holds them, the case name, date and URL are attached as match. | Safe to show. Link it. Still read the case. |
| not_found | There is affirmative evidence that no such citation exists. This is the fabrication signal, and it is only ever raised on positive evidence, never on a mere miss. | Hard stop. This populates verification.fabricated. Do not let the answer ship without a human looking at it. |
| ambiguous | The citation parsed but matched more than one case cluster. note carries the candidate count. | Disambiguate before relying on it. Rolled into verification.unverified. |
| unverified | The library has no record either way, or the citation could not be parsed. note says which. | No signal in either direction. Build this to look clearly different from not_found: it is the common case for reporters the library does not cover. |
not_found means we have evidence the citation does not exist. unverified means we have no evidence either way. A UI that renders them with the same warning icon destroys the value of both. One is a stop sign, the other is a shrug.
How a citation is checked
Library first, with the first confident answer winning.
- Exact match in the fused index. The index knows every citation string it holds across Texas opinions, Texas statutes and Supreme Court opinions. A hit returns
foundwithnote: "in DocketRouter index". This is the fast path. - Query lookup in the fused index. A second, looser index lookup. A hit returns
foundwithnote: "in DocketRouter index (query)". - The citation table. An offline table of reporter citations built from the Free Law Project's public-domain bulk export. A row proves the citation exists; no row proves nothing on its own.
Any failure anywhere in that chain resolves to unverified. There is no path from an outage or a gap in the library to a fabrication claim; not_found is raised only on positive evidence that the citation does not exist.
What gets checked, and what does not
The extractor recognises reporter citations of the form volume reporter page, and then filters to a reporter allowlist. Everything else in the answer passes through unchecked.
| Checked | Not checked |
|---|---|
|
|
This is a citation-existence check. A found status is evidence that the case is real, and no evidence at all that it stands for the proposition it was cited for. Say that in your interface. Lawyers understand the difference and will trust you more for drawing it.
The revise pass
One extra model call, only when a fabrication is found, only when not streaming.
When verification.fabricated is non-empty and docketrouter.revise is true, the same model is asked once to rewrite the answer without the fabricated citations, and the rewrite is verified again. What you receive is the rewritten answer and the second verification report, with revised: true.
| Property | Value |
|---|---|
| Extra calls | At most one, per request. |
| Temperature | 0, regardless of the temperature you sent. |
| Output budget | Up to 2,500 output tokens for the rewrite, independent of your max_tokens. |
| Billing | Billed. It shows up in usage.cost for the request like any other tokens. |
| Streaming | Never runs. See below. |
| Signal | verification.revised is true on a rewritten answer. |
The instruction given to the model names the offending citations and tells it to remove or replace each one with an authority it is certain exists, preferring the retrieved authorities it was given, and to say plainly where no real authority supports a point rather than citing.
revised: true means the model produced a fabrication and we caught it. Treat that as a signal about the request, not as a resolved incident: surface it, and check the second report, because the rewrite is verified but not guaranteed to come back empty-handed.
Streaming is different
By the time a fabrication is detected in a streamed answer, the text is already on the user's screen, so there is nothing to rewrite. Instead of staying silent, DocketRouter appends the warning to the stream itself, where a human will actually see it:
[DocketRouter: citation check failed. These citations could not be found in the reporters and appear fabricated: 999 U.S. 1234. Do not rely on them. Streamed answers cannot be auto-corrected; re-run this request without stream to get a repaired answer.]
verification.revised is always false on a streamed response. If you want automatic repair, do not stream. See Streaming.
The two reports
Citations are checked twice per request, and the two results live in different places. Both use the same CiteCheck shape.
| Field | Covers | When |
|---|---|---|
docketrouter.sources.citations | Citations found in your prompt. | Before the model runs, and shown to it. Up to 8. null when juice is false. |
docketrouter.verification | Citations found in the answer. | After the model runs. Up to 12 unique. null when juice or verify is false. |
{
"checked": [
{ "input": "556 U.S. 662", "status": "found", "note": "in DocketRouter index" },
{ "input": "550 U.S. 544", "status": "found", "note": "in DocketRouter index" }
],
"fabricated": [], // every input whose status is "not_found"
"unverified": [], // every input whose status is "unverified" or "ambiguous"
"revised": false // whether the revise pass rewrote this answer
}{
"input": "556 U.S. 662",
"status": "found",
"match": {
"name": "Ashcroft v. Iqbal",
"citation": ["556 U.S. 662"],
"court": "",
"date": "2009-05-18",
"url": "https://www.courtlistener.com/opinion/…"
}
}Surfacing this to a lawyer
The report is only worth generating if the interface acts on it.
| Report says | Interface |
|---|---|
fabricated is empty and unverified is empty | Show the answer normally, with the checked citations linked and a quiet note that each was verified. |
unverified is non-empty | Amber inline marker on those citations only, with the note text (for example "not in the DocketRouter library") available on hover or expand. Do not degrade the whole answer. |
fabricated is non-empty | Block the normal presentation. Name the citations. Require an explicit action to reveal the text, and log the request_id. |
revised is true | Tell the user the answer was rewritten after a citation check failed. This builds trust rather than eroding it. |
Two counters in your usage log make this measurable over time: citations_checked and citations_not_found per request, plus fakes_caught in the totals. See Usage and billing.
Something here wrong or missing? Mail hello@docketrouter.ai with the request_id and we will fix the docs or the API, whichever is broken.