Verify citations
Check if a citation refers to a real case. Essential for catching AI hallucinations.Endpoint
POST /legal/v1/verify
curl -X POST https://api.case.dev/legal/v1/verify \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "The Court held in Bush v. Gore, 531 U.S. 98 (2000)..."
}'
casedev legal:v1 verify \
--text "The Court held in Bush v. Gore, 531 U.S. 98 (2000)..."
const result = await client.legal.verify({
text: 'The Court held in Bush v. Gore, 531 U.S. 98 (2000)...'
});
console.log(result.summary);
// { total: 1, verified: 1, notFound: 0, multipleMatches: 0 }
for (const citation of result.citations) {
if (citation.status === 'verified') {
console.log(`✓ ${citation.case.name}: ${citation.case.url}`);
} else {
console.log(`✗ ${citation.original}: not found`);
}
}
result = client.legal.v1.verify(
text='The Court held in Bush v. Gore, 531 U.S. 98 (2000)...'
)
print(result.summary)
# { total: 1, verified: 1, not_found: 0, multiple_matches: 0 }
for citation in result.citations:
if citation.status == 'verified':
print(f'✓ {citation.case.name}: {citation.case.url}')
else:
print(f'✗ {citation.original}: not found')
result, _ := client.Legal.V1.Verify(ctx, casedev.LegalV1VerifyParams{
Text: casedev.F("The Court held in Bush v. Gore, 531 U.S. 98 (2000)..."),
})
fmt.Println(result.Summary)
// { Total: 1, Verified: 1, NotFound: 0, MultipleMatches: 0 }
for _, citation := range result.Citations {
if citation.Status == "verified" {
fmt.Printf("✓ %s: %s\n", citation.Case.Name, citation.Case.URL)
} else {
fmt.Printf("✗ %s: not found\n", citation.Original)
}
}
Response
{
"summary": {
"total": 1,
"verified": 1,
"notFound": 0,
"multipleMatches": 0
},
"citations": [
{
"original": "531 U.S. 98",
"span": { "start": 32, "end": 43 },
"status": "verified",
"verificationSource": "courtlistener",
"confidence": 1,
"normalized": "531 U.S. 98",
"case": {
"id": 118365,
"name": "Bush v. Gore",
"shortName": "Bush",
"court": "scotus",
"dateDecided": "2000-12-12",
"parallelCitations": ["121 S. Ct. 525", "148 L. Ed. 2d 388"],
"url": "https://www.courtlistener.com/opinion/118365/bush-v-gore/"
}
}
]
}
Verification statuses
| Status | Meaning |
|---|---|
verified | Citation matches a real case in CourtListener (~10M cases) |
not_found | No match found — likely hallucination or typo |
multiple_matches | Multiple possible matches — review candidates array |
verificationSource and confidence. CourtListener returns confidence: 1.0, while heuristic fallback uses a score based on the source verification signals.
Parse citations from text
Extract and parse Bluebook components from citation text. Use when you have text and need structured citation data.Endpoint
POST /legal/v1/citations
curl -X POST https://api.case.dev/legal/v1/citations \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev legal:v1 get-citations \
--text "See Roe v. Wade, 410 U.S. 113 (1973), overruled by Dobbs v. Jackson, 597 U.S. 215 (2022)."
const result = await client.legal.citations({
text: 'See Roe v. Wade, 410 U.S. 113 (1973), overruled by Dobbs v. Jackson, 597 U.S. 215 (2022).'
});
for (const citation of result.citations) {
console.log(`${citation.normalized}`);
console.log(` Volume: ${citation.components.volume}`);
console.log(` Reporter: ${citation.components.reporter}`);
console.log(` Page: ${citation.components.page}`);
console.log(` Found: ${citation.found}`);
}
result = client.legal.v1.get_citations(
text='See Roe v. Wade, 410 U.S. 113 (1973), overruled by Dobbs v. Jackson, 597 U.S. 215 (2022).'
)
for citation in result.citations:
print(f'{citation.normalized}')
print(f' Volume: {citation.components.volume}')
print(f' Reporter: {citation.components.reporter}')
print(f' Page: {citation.components.page}')
print(f' Found: {citation.found}')
result, _ := client.Legal.V1.GetCitations(ctx, casedev.LegalV1GetCitationsParams{
Text: casedev.F("See Roe v. Wade, 410 U.S. 113 (1973), overruled by Dobbs v. Jackson, 597 U.S. 215 (2022)."),
})
for _, citation := range result.Citations {
fmt.Println(citation.Normalized)
fmt.Printf(" Volume: %d\n", citation.Components.Volume)
fmt.Printf(" Reporter: %s\n", citation.Components.Reporter)
fmt.Printf(" Page: %d\n", citation.Components.Page)
fmt.Printf(" Found: %v\n", citation.Found)
}
Response
{
"citations": [
{
"original": "410 U.S. 113",
"span": { "start": 17, "end": 29 },
"components": {
"caseName": "Roe v. Wade",
"volume": 410,
"reporter": "U.S.",
"page": 113,
"year": 1973,
"court": "scotus"
},
"normalized": "410 U.S. 113",
"found": true
}
]
}
Extract citations from URL
Fetch a document and extract all citations from it. Use when you have a URL and want to analyze what it cites.Endpoint
POST /legal/v1/citations-from-url
citations: This endpoint fetches content from a URL and categorizes citations by type (cases, statutes, regulations). The citations endpoint parses text you provide and returns Bluebook components.
curl -X POST https://api.case.dev/legal/v1/citations-from-url \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev legal:v1 get-citations-from-url \
--url "https://www.courtlistener.com/opinion/118365/bush-v-gore/"
const result = await client.legal.citationsFromUrl({
url: 'https://www.courtlistener.com/opinion/118365/bush-v-gore/'
});
console.log(`Total citations: ${result.totalCitations}`);
console.log(`Cases: ${result.citations.cases.length}`);
console.log(`Statutes: ${result.citations.statutes.length}`);
console.log(`Regulations: ${result.citations.regulations.length}`);
// Most-cited authorities
for (const cite of result.citations.cases.slice(0, 5)) {
console.log(`${cite.citation} (${cite.count} times)`);
}
result = client.legal.v1.get_citations_from_url(
url='https://www.courtlistener.com/opinion/118365/bush-v-gore/'
)
print(f'Total citations: {result.total_citations}')
print(f'Cases: {len(result.citations.cases)}')
print(f'Statutes: {len(result.citations.statutes)}')
print(f'Regulations: {len(result.citations.regulations)}')
# Most-cited authorities
for cite in result.citations.cases[:5]:
print(f'{cite.citation} ({cite.count} times)')
result, _ := client.Legal.V1.GetCitationsFromURL(ctx, casedev.LegalV1GetCitationsFromURLParams{
URL: casedev.F("https://www.courtlistener.com/opinion/118365/bush-v-gore/"),
})
fmt.Printf("Total citations: %d\n", result.TotalCitations)
fmt.Printf("Cases: %d\n", len(result.Citations.Cases))
fmt.Printf("Statutes: %d\n", len(result.Citations.Statutes))
fmt.Printf("Regulations: %d\n", len(result.Citations.Regulations))
// Most-cited authorities
for _, cite := range result.Citations.Cases[:5] {
fmt.Printf("%s (%d times)\n", cite.Citation, cite.Count)
}
Response
{
"url": "https://www.courtlistener.com/opinion/118365/bush-v-gore/",
"title": "Bush v. Gore, 531 U.S. 98 (2000)",
"totalCitations": 15,
"citations": {
"cases": [
{ "type": "usReporter", "citation": "478 U.S. 109", "count": 3 },
{ "type": "federalReporter", "citation": "772 F.2d 1444", "count": 1 }
],
"statutes": [
{ "type": "usc", "citation": "3 U.S.C. § 5", "count": 2 }
],
"regulations": []
},
"externalLinks": ["https://www.law.cornell.edu/uscode/text/3/5"]
}
Citation types
| Type | Description | Example |
|---|---|---|
usReporter | US Supreme Court | 531 U.S. 98 |
federalReporter | Federal Circuit Courts | 123 F.3d 456 |
stateReporter | State Courts | 123 Cal.App.4th 456 |
usc | US Code | 42 U.S.C. § 1983 |
cfr | Code of Federal Regulations | 29 C.F.R. § 1910.134 |
Get full text
Retrieve the full content of a legal document with optional highlights and summary.Endpoint
POST /legal/v1/full-text
curl -X POST https://api.case.dev/legal/v1/full-text \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev legal:v1 get-full-text \
--url "https://www.courtlistener.com/opinion/118365/bush-v-gore/" \
--highlight-query "equal protection" \
--max-characters 50000
const doc = await client.legal.fullText({
url: 'https://www.courtlistener.com/opinion/118365/bush-v-gore/',
highlightQuery: 'equal protection',
maxCharacters: 50000
});
console.log(doc.title);
console.log(`Length: ${doc.characterCount} chars`);
// Relevant passages
for (const highlight of doc.highlights) {
console.log(`> ${highlight}`);
}
doc = client.legal.v1.get_full_text(
url='https://www.courtlistener.com/opinion/118365/bush-v-gore/',
highlight_query='equal protection',
max_characters=50000
)
print(doc.title)
print(f'Length: {doc.character_count} chars')
# Relevant passages
for highlight in doc.highlights:
print(f'> {highlight}')
doc, _ := client.Legal.V1.GetFullText(ctx, casedev.LegalV1GetFullTextParams{
URL: casedev.F("https://www.courtlistener.com/opinion/118365/bush-v-gore/"),
HighlightQuery: casedev.F("equal protection"),
MaxCharacters: casedev.F(int64(50000)),
})
fmt.Println(doc.Title)
fmt.Printf("Length: %d chars\n", doc.CharacterCount)
// Relevant passages
for _, highlight := range doc.Highlights {
fmt.Printf("> %s\n", highlight)
}
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | URL of the legal document |
maxCharacters | number | Max characters to return (1,000-50,000, default 10,000) |
highlightQuery | string | Query to highlight relevant passages |
summaryQuery | string | Query to generate a focused summary |
Resolve jurisdictions
Convert jurisdiction names to IDs for filtering searches and verification.Endpoint
POST /legal/v1/jurisdictions
curl -X POST https://api.case.dev/legal/v1/jurisdictions \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
casedev legal:v1 list-jurisdictions --name california
# Use in search
casedev legal:v1 find \
--query "wrongful termination" \
--jurisdiction california
const result = await client.legal.jurisdictions({ name: 'california' });
for (const j of result.jurisdictions) {
console.log(`${j.name} (${j.id}) - ${j.level}`);
}
// California (california) - state
// Use in search
const cases = await client.legal.find({
query: 'wrongful termination',
jurisdiction: 'california'
});
result = client.legal.v1.list_jurisdictions(name='california')
for j in result.jurisdictions:
print(f'{j.name} ({j.id}) - {j.level}')
# California (california) - state
# Use in search
cases = client.legal.v1.find(
query='wrongful termination',
jurisdiction='california'
)
result, _ := client.Legal.V1.ListJurisdictions(ctx, casedev.LegalV1ListJurisdictionsParams{
Name: casedev.F("california"),
})
for _, j := range result.Jurisdictions {
fmt.Printf("%s (%s) - %s\n", j.Name, j.ID, j.Level)
}
// California (california) - state
// Use in search
cases, _ := client.Legal.V1.Find(ctx, casedev.LegalV1FindParams{
Query: casedev.F("wrongful termination"),
Jurisdiction: casedev.F("california"),
})
Available jurisdictions
| ID | Name | Level |
|---|---|---|
us-federal | US Federal | Federal |
us-scotus | US Supreme Court | Federal |
california | California | State |
new-york | New York | State |
texas | Texas | State |
| … | All 50 states | State |
Common patterns
Verify AI output before display
# Verify the AI-generated text
curl -X POST https://api.case.dev/legal/v1/verify \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "AI generated citation text..."
}'
# If not found, search for a real alternative
curl -X POST https://api.case.dev/legal/v1/find \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"query": "extracted topic from text"
}'
# Verify AI-generated text
casedev legal:v1 verify --text "AI generated citation text..."
# If not found, search for a real alternative
casedev legal:v1 find --query "extracted topic from text"
async function safeDisplayCitation(aiGeneratedText: string) {
const result = await client.legal.verify({ text: aiGeneratedText });
if (result.summary.notFound > 0) {
// AI hallucinated — find a real alternative
const search = await client.legal.find({
query: extractTopic(aiGeneratedText)
});
return { warning: 'Citation corrected', cases: search.candidates };
}
return { verified: true, citations: result.citations };
}
def safe_display_citation(ai_generated_text: str):
result = client.legal.v1.verify(text=ai_generated_text)
if result.summary.not_found > 0:
# AI hallucinated — find a real alternative
search = client.legal.v1.find(query=extract_topic(ai_generated_text))
return {"warning": "Citation corrected", "cases": search.candidates}
return {"verified": True, "citations": result.citations}
// Verify the AI-generated text
result, _ := client.Legal.V1.Verify(ctx, casedev.LegalV1VerifyParams{
Text: casedev.F(aiGeneratedText),
})
if result.Summary.NotFound > 0 {
// AI hallucinated — find a real alternative
search, _ := client.Legal.V1.Find(ctx, casedev.LegalV1FindParams{
Query: casedev.F(extractTopic(aiGeneratedText)),
})
// Use search.Candidates as corrected results
}
// Otherwise, result.Citations contains verified citations
Build a citation checker
curl -X POST https://api.case.dev/legal/v1/citations-from-url \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Extract all citations from the brief
casedev legal:v1 get-citations-from-url \
--url "https://example.com/brief.pdf"
# Verify each citation found
casedev legal:v1 verify --text "531 U.S. 98"
casedev legal:v1 verify --text "410 U.S. 113"
async function checkBrief(documentUrl: string) {
// Extract all citations from the brief
const extracted = await client.legal.citationsFromUrl({ url: documentUrl });
// Verify each case citation
const results = [];
for (const cite of extracted.citations.cases) {
const verification = await client.legal.verify({ text: cite.citation });
results.push({
citation: cite.citation,
count: cite.count,
verified: verification.summary.verified > 0
});
}
return results;
}
def check_brief(document_url: str):
# Extract all citations from the brief
extracted = client.legal.v1.get_citations_from_url(url=document_url)
# Verify each case citation
results = []
for cite in extracted.citations.cases:
verification = client.legal.v1.verify(text=cite.citation)
results.append({
"citation": cite.citation,
"count": cite.count,
"verified": verification.summary.verified > 0,
})
return results
// Extract all citations from the brief
extracted, _ := client.Legal.V1.GetCitationsFromURL(ctx, casedev.LegalV1GetCitationsFromURLParams{
URL: casedev.F(documentURL),
})
// Verify each case citation
for _, cite := range extracted.Citations.Cases {
verification, _ := client.Legal.V1.Verify(ctx, casedev.LegalV1VerifyParams{
Text: casedev.F(cite.Citation),
})
fmt.Printf("%s (×%d) — verified: %v\n",
cite.Citation, cite.Count, verification.Summary.Verified > 0)
}
Get full context for a verified citation
# Verify the citation
curl -X POST https://api.case.dev/legal/v1/verify \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "531 U.S. 98"
}'
# If verified, get full text with highlights
curl -X POST https://api.case.dev/legal/v1/full-text \
-H "Authorization: Bearer $CASEDEV_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://www.courtlistener.com/opinion/118365/bush-v-gore/",
"highlightQuery": "holding"
}'
# Verify the citation
casedev legal:v1 verify --text "531 U.S. 98"
# If verified, get full text with highlights
casedev legal:v1 get-full-text \
--url "https://www.courtlistener.com/opinion/118365/bush-v-gore/" \
--highlight-query "holding"
const verification = await client.legal.verify({ text: '531 U.S. 98' });
if (verification.citations[0].status === 'verified') {
const fullDoc = await client.legal.fullText({
url: verification.citations[0].case.url,
highlightQuery: 'holding'
});
console.log(fullDoc.highlights); // Key passages about the holding
}
verification = client.legal.v1.verify(text='531 U.S. 98')
if verification.citations[0].status == 'verified':
full_doc = client.legal.v1.get_full_text(
url=verification.citations[0].case.url,
highlight_query='holding'
)
print(full_doc.highlights) # Key passages about the holding
verification, _ := client.Legal.V1.Verify(ctx, casedev.LegalV1VerifyParams{
Text: casedev.F("531 U.S. 98"),
})
if verification.Citations[0].Status == "verified" {
fullDoc, _ := client.Legal.V1.GetFullText(ctx, casedev.LegalV1GetFullTextParams{
URL: casedev.F(verification.Citations[0].Case.URL),
HighlightQuery: casedev.F("holding"),
})
fmt.Println(fullDoc.Highlights) // Key passages about the holding
}

