docketrouter
DocumentationBrowse
Concepts

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.

StatusWhat it meansWhat your interface should do
foundThe 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_foundThere 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.
ambiguousThe citation parsed but matched more than one case cluster. note carries the candidate count.Disambiguate before relying on it. Rolled into verification.unverified.
unverifiedThe 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.
The distinction that matters most

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.

  1. 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 found with note: "in DocketRouter index". This is the fast path.
  2. Query lookup in the fused index. A second, looser index lookup. A hit returns found with note: "in DocketRouter index (query)".
  3. 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.

CheckedNot checked
  • 556 U.S. 662, 925 F.3d 1339, 88 Cal. App. 5th 1402
  • Reporters matching U.S., F., S. Ct., Cal., N.Y., P., A., So., N.E., N.W., S.E., S.W., L. Ed.
  • Up to 8 citations found in your prompt
  • Up to 12 unique citations found in the answer
  • Statutes and code sections
  • Rule cites such as Fed. R. Civ. P. 12(b)(6)
  • Case names on their own, with no reporter cite
  • Pin cites, parentheticals and quotations
  • Whether the case says what the answer claims
Existence, not holding

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.

PropertyValue
Extra callsAt most one, per request.
Temperature0, regardless of the temperature you sent.
Output budgetUp to 2,500 output tokens for the rewrite, independent of your max_tokens.
BillingBilled. It shows up in usage.cost for the request like any other tokens.
StreamingNever runs. See below.
Signalverification.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.

A revised answer is still not a clean answer

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:

appended content delta, streaming only
[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.

FieldCoversWhen
docketrouter.sources.citationsCitations found in your prompt.Before the model runs, and shown to it. Up to 8. null when juice is false.
docketrouter.verificationCitations found in the answer.After the model runs. Up to 12 unique. null when juice or verify is false.
docketrouter.verification
{
  "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
}
a match with case detail, expanded
{
  "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 saysInterface
fabricated is empty and unverified is emptyShow the answer normally, with the checked citations linked and a quiet note that each was verified.
unverified is non-emptyAmber 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-emptyBlock the normal presentation. Name the citations. Require an explicit action to reveal the text, and log the request_id.
revised is trueTell 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.