Skip to content

Citations

Citation parsing, validation, and network analysis.

CitationLookup

Parsed citation reference.

interface CitationLookup {
  id: number;
  volume?: number;
  reporter?: string;
  page?: string;
  type?: number;
  cluster_id?: number;
}

Properties

Property Type Description
id number Citation identifier
volume number? Reporter volume number
reporter string? Reporter abbreviation (e.g., "U.S.")
page string? Starting page number
type number? Citation type code
cluster_id number? Linked opinion cluster

OpinionCited

Citation relationship between opinions.

interface OpinionCited {
  id: number;
  citing_opinion_id?: number;
  cited_opinion_id?: number;
  citing_opinion?: string | number;
  cited_opinion?: string | number;
  depth?: number | string;
}

Properties

Property Type Description
id number Relationship identifier
citing_opinion_id number? Opinion that cites
cited_opinion_id number? Opinion being cited
depth number \| string? Citation depth/treatment

Endpoints

Citation Lookup

GET /api/rest/v4/citations/
import type { CitationLookup, PaginatedResponse } from '@types/lawforge__courtlistener';

async function lookupCitation(
  volume: number,
  reporter: string,
  page: string
): Promise<CitationLookup | null> {
  const url = new URL('https://www.courtlistener.com/api/rest/v4/citations/');
  url.searchParams.set('volume', String(volume));
  url.searchParams.set('reporter', reporter);
  url.searchParams.set('page', page);

  const res = await fetch(url, { headers });
  const data: PaginatedResponse<CitationLookup> = await res.json();

  return data.results[0] ?? null;
}

// Look up "347 U.S. 483" (Brown v. Board of Education)
const citation = await lookupCitation(347, 'U.S.', '483');
console.log(`Cluster ID: ${citation?.cluster_id}`);

Citations to Opinion

GET /api/rest/v4/opinions-cited/?cited_opinion={id}
import type { OpinionCited, PaginatedResponse } from '@types/lawforge__courtlistener';

async function getCitingOpinions(opinionId: number): Promise<OpinionCited[]> {
  const url = new URL('https://www.courtlistener.com/api/rest/v4/opinions-cited/');
  url.searchParams.set('cited_opinion', String(opinionId));

  const res = await fetch(url, { headers });
  const data: PaginatedResponse<OpinionCited> = await res.json();
  return data.results;
}

const citations = await getCitingOpinions(12345);
console.log(`Cited by ${citations.length} opinions`);

Examples

Citation Network

import type { OpinionCited } from '@types/lawforge__courtlistener';

interface CitationNetwork {
  opinionId: number;
  citedBy: number[];
  cites: number[];
}

async function buildNetwork(opinionId: number): Promise<CitationNetwork> {
  const API = 'https://www.courtlistener.com/api/rest/v4';

  const [citedByRes, citesRes] = await Promise.all([
    fetch(`${API}/opinions-cited/?cited_opinion=${opinionId}`, { headers }),
    fetch(`${API}/opinions-cited/?citing_opinion=${opinionId}`, { headers })
  ]);

  const citedByData = await citedByRes.json();
  const citesData = await citesRes.json();

  return {
    opinionId,
    citedBy: citedByData.results.map((c: OpinionCited) => c.citing_opinion_id),
    cites: citesData.results.map((c: OpinionCited) => c.cited_opinion_id)
  };
}

const network = await buildNetwork(12345);
console.log(`Cites ${network.cites.length} opinions`);
console.log(`Cited by ${network.citedBy.length} opinions`);

Parse Citation String

function parseCitation(str: string): { volume: number; reporter: string; page: string } | null {
  // Match patterns like "347 U.S. 483" or "123 F.3d 456"
  const match = str.match(/^(\d+)\s+([A-Za-z.]+\d*[A-Za-z.]*)\s+(\d+)$/);

  if (!match) return null;

  return {
    volume: parseInt(match[1]),
    reporter: match[2],
    page: match[3]
  };
}

const parsed = parseCitation('347 U.S. 483');
if (parsed) {
  const citation = await lookupCitation(parsed.volume, parsed.reporter, parsed.page);
  console.log(citation);
}