# CourtListener Scraper (`crawlerbros/courtlistener-scraper`) Actor

Scrape CourtListener, Free Law Project's open database of US case law (8M+ opinions), federal court dockets (60M+ from PACER/RECAP), oral argument audio, and judge biographies. HTTP-only via the official REST API.

- **URL**: https://apify.com/crawlerbros/courtlistener-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Developer tools, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 11 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $3.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## CourtListener Scraper

Scrape **CourtListener** — Free Law Project's open database of US case law (8M+ opinions), federal court dockets (60M+ from PACER/RECAP), oral argument audio recordings, and judge biographies. HTTP-only via the official `courtlistener.com/api/rest/v4/` endpoint. Anonymous reads work for all search modes; an optional API token unlocks single-resource lookups and citation resolution.

### What this actor does

- **11 modes** — search opinions, dockets, RECAP filings, oral arguments; lookup by ID; courts directory; citation resolution; URL fetch
- **Universal IDs** — opinion cluster IDs, docket IDs, person (judge) IDs, court ID slugs
- **Filters** — court, judge, date filed, citation, neutral cite, docket number, precedential status, min citation count
- **PDF & MP3 storage links** — direct CDN URLs for opinion PDFs, RECAP filings, and oral argument audio
- **Empty fields are omitted**

### Modes

| Mode | What it returns | Required input |
|---|---|---|
| `searchOpinions` | Free-text search of US case law | `searchQuery` |
| `searchDockets` | Federal court dockets (RECAP / PACER) | `searchQuery` |
| `searchRecapDocuments` | Individual filings within RECAP dockets | `searchQuery` |
| `searchOralArguments` | Oral argument audio recordings | `searchQuery` |
| `byOpinion` | Single opinion by cluster ID | `opinionId` |
| `byDocket` | Single docket | `docketId` |
| `byJudge` | Judge / person profile | `judgeId` |
| `byCourt` | Single court | `courtId` |
| `listCourts` | All 3,000+ courts indexed by CourtListener | — |
| `citationLookup` | Resolve citation text → opinion clusters (requires `apiToken`) | `citationText` |
| `byUrl` | Fetch by CourtListener URL | `urls` |

### Output per record

Common fields:
- `recordType` — `opinion` / `docket` / `recapDocument` / `oralArgument` / `judge` / `court` / `citationLookup`
- `caseName`, `court`, `courtId`, `courtCitation`
- `dateFiled`, `dateArgued`, `dateTerminated`
- `docketNumber`, `docketId`, `clusterId`
- `courtListenerUrl` — canonical URL
- `absoluteUrl` — relative URL for the resource on CourtListener
- `scrapedAt` — ISO 8601 UTC timestamp

Opinion-specific:
- `judge`, `panel[]`, `status` (Published / Unpublished / Errata / ...)
- `citations[]`, `neutralCite`, `lexisCite`, `scdbId`, `citeCount`
- `siblingOpinionIds[]`
- `opinions[]` (per-opinion sub-records with `id`, `type`, `pdfUrl`, `downloadUrl`, `snippet`, `citesOpinionIds[]`, `perCuriam`, `sha1`)

Docket-specific:
- `assignedTo`, `cause`, `natureOfSuit`, `jurisdictionType`, `juryDemand`, `chapter`
- `parties[]`, `attorneys[]`, `firms[]`
- `pacerCaseId`
- `recapDocuments[]` (id, documentType, shortDescription, pdfUrl, isAvailable, pageCount, ...)

Oral argument-specific:
- `mp3Url`, `downloadUrl`, `durationSeconds`, `fileSizeBytes`
- `audioId`, `judge`

Judge-specific:
- `fullName`, `nameFirst`, `nameMiddle`, `nameLast`, `nameSuffix`
- `dateDob`, `dateDod`, `dobCity`, `dobState`, `gender`, `religion`, `race[]`
- `politicalAffiliations[]`, `abaRatings[]`
- `educations[]` (school, degreeLevel, degreeYear)
- `positions[]` (positionType, court, appointer, dateStart, dateTermination)

Court-specific:
- `id`, `fullName`, `shortName`, `citationString`, `jurisdiction`, `url`
- `startDate`, `endDate`, `inUse`, `hasOpinionScraper`, `hasOralArgumentScraper`
- `parentCourt`, `appealsTo[]`

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `mode` | enum | `searchOpinions` | Mode dispatcher |
| `searchQuery` | string | `first amendment` | Free-text query |
| `court` | enum | `any` | Court ID slug (curated list of major US courts) |
| `judge` | string | – | Judge name filter |
| `filedAfter`, `filedBefore` | YYYY-MM-DD | – | Filing date range |
| `citation` | string | – | Citation text filter |
| `neutralCite` | string | – | Neutral citation filter |
| `docketNumber` | string | – | Docket number text filter |
| `status` | enum | `any` | Precedential status (Published / Unpublished / ...) |
| `orderBy` | enum | `score desc` | Sort order |
| `opinionId` | string | – | Opinion cluster ID (mode=byOpinion) |
| `docketId` | string | – | Docket ID (mode=byDocket) |
| `judgeId` | string | – | Person ID (mode=byJudge) |
| `courtId` | string | – | Court ID slug (mode=byCourt) |
| `citationText` | textarea | – | Citation text to resolve (mode=citationLookup) |
| `urls` | array | – | CourtListener URLs (mode=byUrl) |
| `minCitationCount` | int | – | Drop opinions cited fewer times than this |
| `highlight` | bool | `true` | Include matched snippet text |
| `apiToken` | string (secret) | – | Optional API token (5,000 req/hr) |
| `maxItems` | int | `50` | 1–10000 |

#### Example: Supreme Court free speech cases since 2000

```json
{
  "mode": "searchOpinions",
  "searchQuery": "free speech",
  "court": "scotus",
  "filedAfter": "2000-01-01",
  "status": "Published",
  "orderBy": "citeCount desc",
  "maxItems": 50
}
````

#### Example: 9th Circuit patent dockets 2024

```json
{
  "mode": "searchDockets",
  "searchQuery": "patent infringement",
  "court": "ca9",
  "filedAfter": "2024-01-01",
  "filedBefore": "2024-12-31"
}
```

#### Example: SCOTUS oral arguments

```json
{
  "mode": "searchOralArguments",
  "searchQuery": "miranda rights",
  "court": "scotus"
}
```

#### Example: judge profile

```json
{
  "mode": "byJudge",
  "judgeId": "3045"
}
```

#### Example: list all courts

```json
{
  "mode": "listCourts",
  "maxItems": 5000
}
```

### Use cases

- **Legal research** — pull opinion text for citator analysis, AI legal assistants, research databases
- **Litigation tracking** — monitor RECAP dockets for new filings in patent / IP / antitrust matters
- **Judicial analytics** — judge biography + ABA ratings + appointment data for bench analytics
- **Citator services** — citation graphs from opinion-cites-opinion relationships
- **Oral-argument NLP** — MP3 + snippet text for SCOTUS/circuit court argument analysis
- **Court directory mining** — comprehensive list of US courts with jurisdictional metadata

### FAQ

**Do I need an API token?**  No, for search modes. CourtListener's search API is fully open. A token is required for `byOpinion` / `byDocket` (single-resource endpoints), `citationLookup`, and any rate-limited heavy use. Tokens are free at https://www.courtlistener.com/profile/api/.

**Why do search modes work without a token?**  Free Law Project explicitly publishes the search index for public/research use. Single-record endpoints (`/opinions/{id}/`, `/dockets/{id}/`) are gated to discourage scraping the full database one record at a time.

**What's the difference between `byOpinion` and the search endpoint?**  `byOpinion` looks up a specific cluster ID via `q=cluster_id:N`. It uses search internally so it works without auth. The actor returns the same fields as a search hit.

**What's RECAP?**  RECAP is Free Law Project's project to liberate PACER documents. Every time a paying PACER user views a docket, it's archived to RECAP and made free for everyone forever. CourtListener indexes ~60M filings from 1.4M dockets.

**Are opinion PDFs included?**  Each opinion record includes a `pdfUrl` pointing at `storage.courtlistener.com`. PDFs are publicly accessible.

**Are RECAP filings accessible?**  Most are not — `isAvailable: false` means the document hasn't been purchased yet. `isAvailable: true` records have a free `pdfUrl` you can download.

**How fresh is the data?**  CourtListener scrapes most courts daily; SCOTUS and circuit court opinions appear within hours. Oral arguments appear same-day.

**What's the difference between an opinion and a cluster?**  A *cluster* is a single legal decision. An *opinion* is a piece of writing within that decision (majority, concurrence, dissent). One cluster has 1-N opinions. The actor returns one record per cluster with all sub-opinions nested.

### Limitations

- Single-resource endpoints (`/opinions/{id}/`, `/dockets/{id}/`, `/clusters/{id}/`, `/citation-lookup/`) require an API token. The actor uses search-by-ID (`q=cluster_id:N`) for `byOpinion`/`byDocket` so they work without auth.
- RECAP filings are only downloadable when `isAvailable: true`. Sealed / unpurchased filings show metadata only.
- The full-text snippet is capped at 1,000 characters per opinion to keep payloads reasonable. Use the `pdfUrl` to fetch full text.

# Actor input Schema

## `mode` (type: `string`):

What to fetch from CourtListener. `searchOpinions` is the most common case (full-text case law search). Lookup-by-ID modes need a CourtListener API token.

## `searchQuery` (type: `string`):

Free-text full-text query for any of the four `search*` modes. Example: `first amendment`, `qualified immunity`, `Roe v. Wade`.

## `court` (type: `string`):

Restrict results to a specific court. Use a court ID slug like `scotus`, `ca9`, or `nysd`. Run `mode=listCourts` to see the full directory of 3,000+ courts.

## `judge` (type: `string`):

Restrict by judge name (free-text, e.g. `Sotomayor`, `Roberts`).

## `filedAfter` (type: `string`):

Drop opinions/dockets filed before this date.

## `filedBefore` (type: `string`):

Drop opinions/dockets filed after this date.

## `citation` (type: `string`):

Citation text, e.g. `410 U.S. 113`, `347 U.S. 483`. Use as filter on opinion search OR as direct lookup in `citationLookup` mode (latter requires apiToken).

## `neutralCite` (type: `string`):

Filter opinions by neutral cite, e.g. `2015 WL 1234567`.

## `docketNumber` (type: `string`):

Filter opinions/dockets by docket number text.

## `status` (type: `string`):

Restrict opinions by precedential status.

## `orderBy` (type: `string`):

Result sort order. Defaults to relevance scoring.

## `opinionId` (type: `string`):

Numeric CourtListener opinion cluster ID. Example: `108713`.

## `docketId` (type: `string`):

Numeric CourtListener docket ID.

## `judgeId` (type: `string`):

Numeric CourtListener person ID.

## `courtId` (type: `string`):

CourtListener court ID slug, e.g. `scotus`, `ca9`, `nysd`.

## `citationText` (type: `string`):

Free-text containing one or more citations to resolve (mode=citationLookup, requires apiToken).

## `urls` (type: `array`):

Direct CourtListener URLs (opinion / docket / person / court).

## `minCitationCount` (type: `integer`):

Drop opinions cited fewer times than this.

## `highlight` (type: `boolean`):

If true, include the matched snippet text in each opinion record.

## `apiToken` (type: `string`):

Personal API token from https://www.courtlistener.com/profile/api/. Required for `citationLookup` mode; recommended for high-volume runs (raises rate limits to ~5,000 req/hr). Search modes work fully anonymously.

## `maxItems` (type: `integer`):

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "searchOpinions",
  "searchQuery": "first amendment",
  "court": "any",
  "status": "any",
  "orderBy": "score desc",
  "opinionId": "108713",
  "urls": [],
  "highlight": true,
  "maxItems": 50
}
```

# Actor output Schema

## `records` (type: `string`):

Dataset containing all scraped records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mode": "searchOpinions",
    "searchQuery": "first amendment",
    "court": "any",
    "status": "any",
    "orderBy": "score desc",
    "urls": [],
    "highlight": true,
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/courtlistener-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "mode": "searchOpinions",
    "searchQuery": "first amendment",
    "court": "any",
    "status": "any",
    "orderBy": "score desc",
    "urls": [],
    "highlight": True,
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/courtlistener-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mode": "searchOpinions",
  "searchQuery": "first amendment",
  "court": "any",
  "status": "any",
  "orderBy": "score desc",
  "urls": [],
  "highlight": true,
  "maxItems": 50
}' |
apify call crawlerbros/courtlistener-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/courtlistener-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "CourtListener Scraper",
        "description": "Scrape CourtListener, Free Law Project's open database of US case law (8M+ opinions), federal court dockets (60M+ from PACER/RECAP), oral argument audio, and judge biographies. HTTP-only via the official REST API.",
        "version": "1.0",
        "x-build-id": "zl4tbLrDK2gSIeZaB"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/crawlerbros~courtlistener-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-crawlerbros-courtlistener-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/crawlerbros~courtlistener-scraper/runs": {
            "post": {
                "operationId": "runs-sync-crawlerbros-courtlistener-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/crawlerbros~courtlistener-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-crawlerbros-courtlistener-scraper",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "mode"
                ],
                "properties": {
                    "mode": {
                        "title": "Mode",
                        "enum": [
                            "searchOpinions",
                            "searchDockets",
                            "searchRecapDocuments",
                            "searchOralArguments",
                            "byOpinion",
                            "byDocket",
                            "byJudge",
                            "byCourt",
                            "listCourts",
                            "citationLookup",
                            "byUrl"
                        ],
                        "type": "string",
                        "description": "What to fetch from CourtListener. `searchOpinions` is the most common case (full-text case law search). Lookup-by-ID modes need a CourtListener API token.",
                        "default": "searchOpinions"
                    },
                    "searchQuery": {
                        "title": "Search query",
                        "type": "string",
                        "description": "Free-text full-text query for any of the four `search*` modes. Example: `first amendment`, `qualified immunity`, `Roe v. Wade`.",
                        "default": "first amendment"
                    },
                    "court": {
                        "title": "Court (filter)",
                        "enum": [
                            "any",
                            "scotus",
                            "ca1",
                            "ca2",
                            "ca3",
                            "ca4",
                            "ca5",
                            "ca6",
                            "ca7",
                            "ca8",
                            "ca9",
                            "ca10",
                            "ca11",
                            "cadc",
                            "cafc",
                            "nyed",
                            "nynd",
                            "nysd",
                            "nywd",
                            "cacd",
                            "caed",
                            "cand",
                            "casd",
                            "txed",
                            "txnd",
                            "txsd",
                            "txwd",
                            "ilnd",
                            "dcd",
                            "cal",
                            "ny",
                            "tex",
                            "fla",
                            "ill",
                            "pa",
                            "calctapp",
                            "nyappdiv",
                            "texapp",
                            "cit",
                            "cofc",
                            "tax",
                            "uscfc"
                        ],
                        "type": "string",
                        "description": "Restrict results to a specific court. Use a court ID slug like `scotus`, `ca9`, or `nysd`. Run `mode=listCourts` to see the full directory of 3,000+ courts.",
                        "default": "any"
                    },
                    "judge": {
                        "title": "Judge (filter)",
                        "type": "string",
                        "description": "Restrict by judge name (free-text, e.g. `Sotomayor`, `Roberts`)."
                    },
                    "filedAfter": {
                        "title": "Filed after (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Drop opinions/dockets filed before this date."
                    },
                    "filedBefore": {
                        "title": "Filed before (YYYY-MM-DD)",
                        "type": "string",
                        "description": "Drop opinions/dockets filed after this date."
                    },
                    "citation": {
                        "title": "Citation (filter or lookup)",
                        "type": "string",
                        "description": "Citation text, e.g. `410 U.S. 113`, `347 U.S. 483`. Use as filter on opinion search OR as direct lookup in `citationLookup` mode (latter requires apiToken)."
                    },
                    "neutralCite": {
                        "title": "Neutral citation",
                        "type": "string",
                        "description": "Filter opinions by neutral cite, e.g. `2015 WL 1234567`."
                    },
                    "docketNumber": {
                        "title": "Docket number filter",
                        "type": "string",
                        "description": "Filter opinions/dockets by docket number text."
                    },
                    "status": {
                        "title": "Precedential status (opinion search)",
                        "enum": [
                            "any",
                            "Published",
                            "Unpublished",
                            "Errata",
                            "Separate",
                            "In-chambers",
                            "Relating-to",
                            "Unknown"
                        ],
                        "type": "string",
                        "description": "Restrict opinions by precedential status.",
                        "default": "any"
                    },
                    "orderBy": {
                        "title": "Sort by",
                        "enum": [
                            "score desc",
                            "dateFiled desc",
                            "dateFiled asc",
                            "dateArgued desc",
                            "dateArgued asc",
                            "citeCount desc",
                            "citeCount asc",
                            "name_reverse asc"
                        ],
                        "type": "string",
                        "description": "Result sort order. Defaults to relevance scoring.",
                        "default": "score desc"
                    },
                    "opinionId": {
                        "title": "Opinion / cluster ID (mode=byOpinion)",
                        "type": "string",
                        "description": "Numeric CourtListener opinion cluster ID. Example: `108713`."
                    },
                    "docketId": {
                        "title": "Docket ID (mode=byDocket)",
                        "type": "string",
                        "description": "Numeric CourtListener docket ID."
                    },
                    "judgeId": {
                        "title": "Judge / person ID (mode=byJudge)",
                        "type": "string",
                        "description": "Numeric CourtListener person ID."
                    },
                    "courtId": {
                        "title": "Court ID (mode=byCourt)",
                        "type": "string",
                        "description": "CourtListener court ID slug, e.g. `scotus`, `ca9`, `nysd`."
                    },
                    "citationText": {
                        "title": "Citation text to resolve (mode=citationLookup)",
                        "type": "string",
                        "description": "Free-text containing one or more citations to resolve (mode=citationLookup, requires apiToken)."
                    },
                    "urls": {
                        "title": "CourtListener URLs (mode=byUrl)",
                        "type": "array",
                        "description": "Direct CourtListener URLs (opinion / docket / person / court).",
                        "default": [],
                        "items": {
                            "type": "string"
                        }
                    },
                    "minCitationCount": {
                        "title": "Min citation count (filter)",
                        "minimum": 0,
                        "maximum": 1000000,
                        "type": "integer",
                        "description": "Drop opinions cited fewer times than this."
                    },
                    "highlight": {
                        "title": "Include search snippet highlights",
                        "type": "boolean",
                        "description": "If true, include the matched snippet text in each opinion record.",
                        "default": true
                    },
                    "apiToken": {
                        "title": "CourtListener API token (optional)",
                        "type": "string",
                        "description": "Personal API token from https://www.courtlistener.com/profile/api/. Required for `citationLookup` mode; recommended for high-volume runs (raises rate limits to ~5,000 req/hr). Search modes work fully anonymously."
                    },
                    "maxItems": {
                        "title": "Max items",
                        "minimum": 1,
                        "maximum": 10000,
                        "type": "integer",
                        "description": "Hard cap on emitted records.",
                        "default": 50
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
