openapi: 3.0.1 info: title: Midpage Legal Database API description: >- REST API for Midpage's US legal database ("Caselaw Building Blocks"). Search court opinions with semantic (vector), keyword (full-text), or hybrid search; retrieve full opinion data by ID, citation, or docket number with citator treatments; and read the authenticated user's identity and subscription status. Authenticate with a bearer token (API key) in the Authorization header. termsOfService: https://www.midpage.ai/ contact: name: Midpage url: https://www.midpage.ai/ version: '1.0' servers: - url: https://app.midpage.ai/api/v1 description: Production server security: - apiKey: [] paths: /search: post: operationId: searchOpinions tags: - Search summary: Search opinions description: >- Search for opinions using semantic (vector), keyword (full-text), or hybrid search. Search modes: `semantic` (vector similarity using AI embeddings), `keyword` (Elasticsearch full-text with Lexis/Westlaw-style boolean operators), and `hybrid` (semantic + keyword combined with reciprocal rank fusion and deduplication). Boolean operators (keyword mode only, must be UPPERCASE): AND, OR, NOT, "..." (exact phrase), * and ? (wildcards), W/n (proximity within n words), and () for grouping. Pagination uses `page` (1-indexed) and `page_size` (max 100). Semantic search supports limited deep pagination (~500 unique results); keyword and hybrid support deep pagination via Elasticsearch. requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SearchRequest' responses: '200': description: Search results content: application/json: schema: $ref: '#/components/schemas/SearchResponse' '400': description: Bad request content: application/json: schema: type: object properties: error: type: string example: query is required and must be a string '401': description: Unauthorized content: application/json: schema: type: object properties: error: type: string example: Unauthorized message: type: string example: Invalid API key /opinions/get: post: operationId: getOpinions tags: - Opinions summary: Get opinions description: >- Retrieve full opinion data by ID, citation, or docket number. Supports bulk reads of up to 100 items per request. Provide exactly one of `opinion_ids`, `citations`, or `docket` (not multiple). Lookup methods: `opinion_ids` (direct lookup, up to 100), `citations` (reporter citation, case-insensitive, up to 100), and `docket` (docket number + court; single lookup, may return multiple opinions). When using `citations` or `docket`, a lookup may match multiple opinions (e.g., majority and dissent from the same case). The response includes `citation_matches` or `docket_matches` arrays showing which lookups matched which opinion IDs. requestBody: required: true content: application/json: schema: type: object properties: opinion_ids: type: array items: type: string description: Array of opinion IDs to retrieve example: - '8623588' - '1865773' citations: type: array items: type: string description: Array of citation strings to look up (case-insensitive) example: - 556 U.S. 662 - 550 U.S. 544 docket: $ref: '#/components/schemas/DocketLookup' include_content: type: boolean default: false description: Include full HTML content include_detailed_treatments: type: boolean default: false description: Include citator treatments responses: '200': description: Opinion data content: application/json: schema: type: object properties: opinions: type: array items: $ref: '#/components/schemas/OpinionFull' citation_matches: type: array items: $ref: '#/components/schemas/CitationMatch' description: >- Only present when looking up by `citations`. Shows which citations matched which opinion IDs. docket_matches: type: array items: $ref: '#/components/schemas/DocketMatch' description: >- Only present when looking up by `docket`. Shows which opinions matched. '400': description: Bad request content: application/json: schema: type: object properties: error: type: string example: >- Must provide one of: opinion_ids, citations (as arrays), or docket (object with docket_number) /me: get: operationId: getCurrentUser tags: - User summary: Get current user description: >- Retrieve the authenticated user's Midpage identity and current subscription status. Authenticate with a bearer token in the Authorization header. Supported bearer tokens: OAuth access token or API key. Common subscription statuses: `active`, `trialing`, `past_due`, `canceled`. If no subscription status is available, `subscriptionStatus` may be `null`. responses: '200': description: Current user profile content: application/json: schema: $ref: '#/components/schemas/CurrentUserResponse' '401': description: Unauthorized content: application/json: schema: type: object properties: error: type: string example: Unauthorized components: securitySchemes: apiKey: type: http scheme: bearer description: >- API key authentication. Get your API key from the Midpage Developer Portal at https://app.midpage.ai/developers schemas: CurrentUserResponse: type: object required: - userId - subscriptionStatus properties: userId: type: string description: Midpage user identifier example: user_123 subscriptionStatus: type: string nullable: true description: >- Current subscription status. Common values include `active`, `trialing`, `past_due`, and `canceled`. May be `null` if no subscription status is available. example: active SearchRequest: type: object required: - query properties: query: type: string description: Search query text example: breach of fiduciary duty mode: type: string enum: - semantic - keyword - hybrid default: semantic description: >- Search mode: `semantic` (vector similarity, default), `keyword` (full-text), or `hybrid` (combined semantic and keyword results using reciprocal rank fusion). page: type: integer minimum: 1 default: 1 description: Page number (1-indexed) page_size: type: integer minimum: 1 maximum: 100 default: 20 description: Results per page (max 100) filters: $ref: '#/components/schemas/SearchFilters' include_facets: type: boolean default: false description: >- Include facet breakdowns in the response showing result counts by court, jurisdiction, state, and year. Facets are only available in `keyword` and `hybrid` modes (not `semantic`). In `hybrid` mode, facet counts reflect keyword search results only. SearchFilters: type: object description: Optional filters to narrow search results properties: court_ids: type: array items: type: string description: Filter by court IDs (e.g., "ca9", "scotus", "nysd") example: - ca9 - ca2 jurisdictions: type: array items: type: string enum: - Federal Appellate - Federal District - State Supreme - State Appellate - State Trial - Federal Bankruptcy - Federal Bankruptcy Panel - Federal Special - Military Appellate - State Attorney General - State Special - U.S. Territory - Committee - International - Tribal - Tribal Appellate - Tribal Supreme - Tribal Trial description: >- Filter by jurisdiction type using canonical values from Midpage court metadata. example: - Federal Appellate - State Supreme states: type: array items: type: string description: >- Filter by state using full canonical names from Midpage court metadata. example: - California - New York publish_status: type: string description: >- Filter by publication status. Use `unknown` to include opinions where publication metadata is missing or uncertain. enum: - published - unpublished - unknown - in_chambers - separate - errata - relating_to example: published date_filed: type: object description: Filter by filing date range properties: start: type: string format: date description: Start date (YYYY-MM-DD) example: '2020-01-01' end: type: string format: date description: End date (YYYY-MM-DD) example: '2024-12-31' SearchResponse: type: object properties: results: type: array items: $ref: '#/components/schemas/SearchResultItem' pagination: $ref: '#/components/schemas/PaginationMeta' metadata: type: object properties: mode: type: string enum: - semantic - keyword - hybrid description: Search mode used query: type: string description: Original query processing_time_ms: type: integer description: Server processing time in milliseconds boolean_query: type: object description: Present in keyword mode when boolean operators are detected properties: detected: type: boolean description: Whether boolean operators were detected operators: type: array items: type: string description: List of detected operators (e.g., ["AND", "OR", "W/5"]) facets: $ref: '#/components/schemas/SearchFacets' SearchFacets: type: object description: >- Facet breakdowns showing result counts by various dimensions. Only present when `include_facets: true` in request and mode is `keyword` or `hybrid`. Counts are computed across the full result set (after filters), not just the current page. properties: court_abbreviation: type: array items: $ref: '#/components/schemas/FacetBucket' description: Breakdown by court abbreviation (e.g., "9th Cir.", "S.D.N.Y.") jurisdiction: type: array items: $ref: '#/components/schemas/FacetBucket' description: Breakdown by jurisdiction type state: type: array items: $ref: '#/components/schemas/FacetBucket' description: Breakdown by state name year_filed: type: array items: $ref: '#/components/schemas/FacetBucket' description: Breakdown by filing year note: type: string description: Explanatory note about facet limitations. example: >- Facet counts reflect keyword search results only; semantic (Pinecone) results are not included in these counts. FacetBucket: type: object description: A single bucket in a facet breakdown properties: key: type: string description: The value (e.g., "9th Cir.", "Federal Appellate", "2024") count: type: integer description: Number of documents matching this value SearchResultItem: type: object properties: opinion_id: type: string description: Opinion identifier score: type: number description: >- Relevance score. Scale varies by mode: semantic 0-1 (cosine similarity), keyword 0-100+ (BM25 score). case_name: type: string description: Case name/caption court_id: type: string description: Court identifier court_name: type: string description: Full court name court_abbreviation: type: string description: Court citation abbreviation jurisdiction: type: string description: Jurisdiction type state: type: string nullable: true description: State name (null for federal courts) publish_status: type: string nullable: true description: Publication status, when available enum: - published - unpublished - unknown - in_chambers - separate - errata - relating_to date_filed: type: string format: date description: Filing date (YYYY-MM-DD) docket_number: type: string nullable: true description: Court docket number, when available snippet: type: string description: Relevant text excerpt from the opinion source: type: string enum: - semantic - keyword description: >- Source of this result. Always present in API responses: semantic mode "semantic", keyword mode "keyword", hybrid mode varies per item. PaginationMeta: type: object properties: page: type: integer description: Current page number page_size: type: integer description: Results per page total_results: type: integer description: Total matching results (capped at 10,000 for keyword/hybrid) total_pages: type: integer description: Total pages available has_next: type: boolean description: Whether more pages exist has_prev: type: boolean description: Whether previous pages exist OpinionFull: type: object properties: id: type: string description: Opinion identifier case_name: type: string description: Case name/caption court_id: type: string description: Court identifier court_abbreviation: type: string description: Citation abbreviation docket_number: type: string description: Court docket number date_filed: type: string format: date description: Filing date state: type: string nullable: true description: State name (null for federal courts) publish_status: type: string enum: - published - unpublished - unknown - in_chambers - separate - errata - relating_to description: >- Publication status for the opinion. Missing or uncertain metadata is returned as unknown. judge_name: type: string description: Authoring judge citations: type: array items: $ref: '#/components/schemas/Citation' citation_count: type: integer description: Number of times this opinion is cited by other opinions overall_treatment: type: string nullable: true enum: - Negative - Caution - Neutral description: >- Most negative treatment category from all citing opinions. Always returned. Priority: Negative > Caution > Neutral > null (no treatment data). treatments: type: array items: $ref: '#/components/schemas/Treatment' description: >- Citator treatments (only included if include_detailed_treatments=true) html_content: type: string description: Full opinion text in HTML (only included if include_content=true) Citation: type: object properties: cited_as: type: string description: Full citation string volume: type: string description: Reporter volume reporter: type: string description: Reporter abbreviation page: type: string description: Starting page Treatment: type: object properties: citing_id: type: string description: ID of opinion citing this one treatment_category: type: string description: Treatment type treatment_description: type: string description: Detailed treatment is_authoritative: type: boolean description: Whether authoritative supporting_quote: type: string description: Quote supporting the treatment CitationMatch: type: object description: Maps a requested citation to the opinion(s) it matched properties: citation: type: string description: The citation string from the request example: 556 U.S. 662 opinion_id: type: string description: The matched opinion ID example: '145875' DocketLookup: type: object description: >- Lookup by docket number and court. Requires docket_number and either court_id or court_abbreviation. required: - docket_number properties: docket_number: type: string description: The docket number (e.g., "19-1392", "1:23-cv-01234") example: 19-1392 court_id: type: string description: Court identifier (e.g., "scotus", "ca9", "nysd") example: scotus court_abbreviation: type: string description: Court citation abbreviation (e.g., "SCOTUS", "9th Cir.", "S.D.N.Y.") example: SCOTUS DocketMatch: type: object description: Maps a docket lookup to the opinion(s) it matched properties: docket_number: type: string description: The docket number that matched example: 19-1392 court_id: type: string description: Court identifier example: scotus court_abbreviation: type: string description: Court citation abbreviation example: SCOTUS opinion_id: type: string description: The matched opinion ID example: '145875'