▸ Contents
API Reference
The Open Publica API is free and needs no key. It powers this site: search and read US local-government meetings, pull AI summaries and full transcripts, and find which governments we cover near any place. Every route is a plain GET that returns JSON.
curl 'https://api.openpublica.com/v1/meetings?limit=1'Conventions
Every success returns { data, meta } — both keys always present. data is the object or array you asked for; meta carries count, limit, page, and mode.
GET /v1 with no path returns an index of every route, so the surface is browsable without leaving your terminal.
start_date and end_date are ISO YYYY-MM-DD, inclusive. Meetings carry both an ISO date and epoch_timestamp in Unix seconds (UTC).
Every coordinate is [longitude, latitude] — GeoJSON order, not lat/lng. That applies to near= and to a government's location.
limit everywhere; page (1-based) where offset paging exists. meta.has_more tells you whether another page is waiting.
The gateway comma-joins repeated query keys, so only government_ids, fields, and near are parsed as comma-separated lists.
Send Accept-Encoding: gzip and anything over ~1 KB comes back gzipped. Listings are mostly prose and compress about 10x, so it is worth setting on any bulk read.
On /v1/meetings, fields= names exactly what to return and nothing else is read. A full meeting is ~7 KB, so a 100-record page drops from ~700 KB to ~20 KB.
Errors
Failures return a matching HTTP status and a single-shape body: {"error": {"message": "..."}}. A missing entity is a real 404 rather than a 200 with a null payload, so you can branch on the status alone.
400A parameter is missing or malformed — no q on search, a non-ISO date, or more than one government selector.
404Unknown meeting or government id, an unresolvable postal code, or a route that doesn't exist.
405v1 is GET-only. The response carries Allow: GET.
429Throttled. The response carries Retry-After — wait that many seconds before retrying.
500Something failed on our side. Retry with backoff.
The meeting object
Returned by every meeting route. Search results add scoring fields on top. Extra fields may appear over time — tolerate them.
meeting_idCanonical id. The only value the meeting routes accept.
government_idThe government this meeting belongs to.
titleMeeting title as filed.
dateMeeting date, ISO YYYY-MM-DD (UTC).
epoch_timestampThe same moment in Unix seconds — multiply by 1000 for a JS Date.
summaryThe AI summary of proceedings, as markdown.
category_nameHuman-readable meeting body, e.g. "City Council".
category_tagOpaque UUID for that body — the value the category_tag filter takes.
topicsObjects of { topic, conversation_percentage } — the discussion breakdown.
video_urlArchived recording. Null until the deferred Internet Archive upload lands.
source_urlOriginal government link. The fallback for playback while video_url is null.
thumbnail_urlStill frame for the meeting.
transcript_urlJSON of timestamped transcript segments. Fetch it directly.
relevance_scoreSemantic match strength. Search results only.
keyword_scoreBM25 match strength. Keyword and hybrid results only.
highlightsMatched snippets. Keyword and hybrid results only.
The government object
Returned by every government route. A government is a city, county, or district whose meetings we track.
government_idCanonical id, e.g. "sacramento_county-california".
nameDisplay name, e.g. "Sacramento County, California".
cityCity or county component of the name, lowercase.
stateState component, lowercase.
locationGeoJSON point — { type, coordinates: [longitude, latitude] }.
categoriesTracked meeting bodies: { name, tag, data_source, playlist_url }.
topicsTopic names seen across this government's meetings.
imageUrlGovernment seal or icon. Note the camelCase — it predates the v1 renames.
weekly_summaryMarkdown digest of the week. Only with include_weekly_summary=true.
The document object
Returned by the document routes. A document is one adopted publication — a general-plan element, a bound plan, or a budget — pinned to the government that adopted it. Which fields appear depends on status, so read that first.
idDocument id — what the /v1/documents routes take. Search results spell it document_id.
government_idThe government that published it.
titleThe document's own title, as published.
statusWhat this entry offers: converted, superseded, or failed. See below.
coversEvery plan slot this document answers for — a bound plan expands to all eight elements.
source_urlThe government's own copy. Always present, including on a failed entry; cite it.
verified_onDate we last confirmed the pin points at this document.
checked_atDate we last looked at it.
page_countPages in the source PDF. Absent on a failed document.
doc_typeOnly on documents that carry one (budgets and the like); absent on general-plan elements.
availabilityPresent ONLY when something is wrong — its presence is the signal. Carries complete, reason, and problems.
superseded_byThe edition that retired this one. Only on a superseded document.
markdown_urlThe whole document as markdown. Only on GET /v1/documents/{id}.
List meetings
/v1/meetingsReturns a page of processed meetings, newest first. Scope to one government with government_id, or omit it to draw from every government at once.
government_idScope to one government, e.g. "sacramento_county-california".
category_tagFilter to one meeting body. An opaque UUID — read it from /v1/vocabulary rather than guessing.
topicOnly meetings that discussed this topic, e.g. "Affordable Housing".
start_dateEarliest meeting date, ISO YYYY-MM-DD (inclusive).
end_dateLatest meeting date, ISO YYYY-MM-DD (inclusive).
limitResults per page, 1–100. Defaults to 10.
page1-based page index. Defaults to 1; meta.has_more signals another page.
fieldsComma-separated sparse fieldset — each record comes back with only these fields. A full meeting is ~7 KB, so a bulk walk that needs a few scalars should say so.
curl 'https://api.openpublica.com/v1/meetings?government_id=sacramento_county-california&limit=5'{
"data": [
{
"meeting_id": "6a5b0a986b2c35938e9a89aa",
"government_id": "bellevue-washington",
"title": "Bellevue City Council Meeting — July 17, 2026",
"date": "2026-07-17",
"epoch_timestamp": 1784313900,
"category_name": "City Council",
"category_tag": "c125a28d-4898-4276-ac9c-21050c767352",
"summary": "# Bellevue City Council Meeting...",
"video_url": "https://archive.org/download/.../meeting.mp4",
"source_url": "https://bellevue.granicus.com/...",
"thumbnail_url": "https://.../thumbnails/31127b60.webp",
"transcript_url": "https://.../transcriptions/31127b60.json",
"topics": [
{ "topic": "Economic Development", "conversation_percentage": 29 }
]
}
],
"meta": { "count": 5, "limit": 5, "page": 1, "has_more": true }
}Search meetings
/v1/meetings/searchSearches every meeting summary. semantic matches by meaning, keyword matches exact terms such as ordinance numbers or names, and hybrid rank-fuses both. Semantic hits carry relevance_score; keyword and hybrid hits add keyword_score and highlights.
qThe query — natural language, or exact terms in keyword mode.
mode"semantic" (default), "keyword", or "hybrid".
government_idScope to one government.
government_idsComma-separated ids to search several governments at once. Overrides government_id.
category_tagMeeting-body filter — an opaque UUID from /v1/vocabulary.
topicOnly meetings that discussed this topic.
min_scoreRelevance floor for semantic matches, 0–1.
start_dateEarliest meeting date, ISO YYYY-MM-DD.
end_dateLatest meeting date, ISO YYYY-MM-DD.
limitMax results, 1–25. Defaults to 10.
curl 'https://api.openpublica.com/v1/meetings/search?q=affordable+housing&mode=hybrid&limit=5'{
"data": [
{
"meeting_id": "6a5ba563566bda5aeed771be",
"government_id": "san_antonio-texas",
"title": "Public Hearing on FY2026 Affordable Housing Action Plan",
"date": "2026-04-15",
"epoch_timestamp": 1776211200,
"summary": "# San Antonio City Council Public Hearing...",
"video_url": null,
"source_url": "https://sanantoniotx.new.swagit.com/videos/382391/download",
"topics": [
{ "topic": "Affordable Housing", "conversation_percentage": 85 }
],
"relevance_score": 0.7152,
"keyword_score": 14.2758,
"highlights": ["Affordable Housing"]
}
],
"meta": { "count": 5, "limit": 5, "match_type": "hybrid" }
}Retrieve a meeting
/v1/meetings/{id}Returns one meeting in full — the complete AI summary, topic breakdown, and the transcript_url holding the raw timestamped segments. Responds 404 if the id is unknown.
idThe meeting_id from a list or search result.
curl 'https://api.openpublica.com/v1/meetings/6a5b0a986b2c35938e9a89aa'{
"data": {
"meeting_id": "6a5b0a986b2c35938e9a89aa",
"government_id": "bellevue-washington",
"title": "Bellevue City Council Meeting — July 17, 2026",
"date": "2026-07-17",
"epoch_timestamp": 1784313900,
"category_name": "City Council",
"summary": "# Bellevue City Council Meeting...",
"video_url": "https://archive.org/download/.../meeting.mp4",
"source_url": "https://bellevue.granicus.com/...",
"transcript_url": "https://.../transcriptions/31127b60.json",
"topics": [
{ "topic": "Historic Preservation", "conversation_percentage": 14 }
]
},
"meta": {}
}Find governments
/v1/governmentsFinds tracked governments three ways — pass at most one selector. q runs a name typeahead, near sorts by distance from a coordinate, and postal_code geocodes a ZIP then searches around it. With no selector you get an alphabetical page, which is what a city picker wants. meta.mode reports which selector ran.
qName search, e.g. "sacramento" or "texas".
near"lon,lat" — GeoJSON order, longitude first, e.g. -121.49,38.58.
postal_codeZIP to geocode and search around. Unknown ZIP responds 404.
country_codeISO country code for postal_code. Defaults to "US".
limitMax results, 1–50. Defaults to 10.
page1-based page index. Name and alphabetical modes only.
curl 'https://api.openpublica.com/v1/governments?postal_code=95814'{
"data": [
{
"government_id": "sacramento_county-california",
"name": "Sacramento County, California",
"city": "sacramento county",
"state": "california",
"location": { "type": "Point", "coordinates": [-121.4418, 38.5692] },
"categories": [
{
"name": "Board of Supervisors",
"tag": "7e36f7b9-9156-42ba-a65b-7af71221626d",
"data_source": "youtube"
}
],
"topics": ["Homelessness", "Affordable Housing"]
}
],
"meta": {
"mode": "postal",
"resolved_location": {
"postal_code": "95814",
"place_name": "Sacramento",
"state_name": "California",
"coordinates": [-121.4944, 38.5816]
},
"count": 1,
"limit": 10
}
}Retrieve a government
/v1/governments/{id}Returns one government's profile — display name, location, and the meeting bodies tracked for it. Ask for the AI weekly digest with include_weekly_summary. Responds 404 if the id is unknown.
idThe government_id to look up.
include_weekly_summaryPass true to include the markdown weekly digest.
curl 'https://api.openpublica.com/v1/governments/sacramento_county-california?include_weekly_summary=true'{
"data": {
"government_id": "sacramento_county-california",
"name": "Sacramento County, California",
"city": "sacramento county",
"state": "california",
"location": { "type": "Point", "coordinates": [-121.4418, 38.5692] },
"weekly_summary": "## This week\nThe board approved..."
},
"meta": {}
}Retrieve activity stats
/v1/governments/{id}/statsReturns a meeting-activity rollup over a recent window: the total, a per-day histogram, and the most active meeting bodies. Pass "all" as the id for corpus-wide numbers.
idA government_id, or "all" for every government.
daysLook-back window in days, 1–365. Defaults to 30.
curl 'https://api.openpublica.com/v1/governments/all/stats?days=7'{
"data": {
"government_id": "all",
"total_meetings": 196,
"activity_by_day": { "2026-07-13": 24, "2026-07-14": 68 },
"categories": [
{
"name": "City Council",
"count": 103,
"tags": ["c125a28d-4898-4276-ac9c-21050c767352"]
}
]
},
"meta": { "days": 7 }
}Status & coverage
We hold adopted general plans and budgets as page-cited text. Two fields decide what a response actually claims, and both are easy to misread — worth a minute before calling the routes below.
convertedCurrently served: searchable, and readable by page range.
supersededReplaced by a newer edition. Still stored and listable with include_superseded, but neither searchable nor readable.
failedWe hold this pin and could not read the document — NOT that the government published nothing. source_url still points at the city's own copy.
pinnedWe have pinned documents here. coverage.pinned_slots names which slots were looked for, which is not everything a city publishes.
reviewed_none_pinnedWe reviewed this government and pinned nothing.
unavailableReview was not possible; coverage.reason says why.
not_reviewedWe have not reviewed this government. Most tracked governments are here — an empty data is then a fact about OpenPublica, not about the city.
nullThe government was added since the coverage projection last ran. Not the same claim as not_reviewed, so don't collapse the two.
Coverage is what makes an empty data readable. Without it, “this government publishes nothing” and “we have never looked here” are the same response — and most tracked governments are the second.
A city that binds its whole general plan into one PDF gets pinned as combined, and that single document genuinely answers for all eight elements. covers names every slot it answers for; element, which appears on search hits, names only whichever pin acquired it. Read element alone and the rest of a city's plan looks unpublished.
List a government's documents
/v1/governments/{id}/documentsThe adopted general-plan and budget documents held for one government. Read meta.coverage alongside data — it is what separates "this government publishes nothing" from "we have not looked here yet", and most tracked governments are the latter.
idThe government_id to list documents for.
include_supersededPass true to include editions retired by a newer one. Defaults to false.
limitMax documents, 1–50 (also the default).
curl 'https://api.openpublica.com/v1/governments/san_antonio-texas/documents'{
"data": [
{
"id": "9ad60b2d997f9c06b136ccfba64f3e2466589d59c22b3d66d2c7a9800a208186",
"government_id": "san_antonio-texas",
"title": "SA Tomorrow Comprehensive Plan (Adopted August 11, 2016)",
"status": "converted",
"covers": [
"circulation", "combined", "conservation", "ej", "housing",
"land_use", "noise", "open_space", "safety"
],
"source_url": "https://sacompplan.com/new_docs/SA_CompPlan_FULLDoc.pdf",
"verified_on": "2026-08-17",
"checked_at": "2026-08-18",
"page_count": 330
}
],
"meta": {
"count": 1,
"limit": 50,
"coverage": {
"state": "pinned",
"pinned_slots": ["combined"],
"seed_url": "https://sacompplan.com/",
"reason": null,
"last_reviewed": "2026-08-17"
}
}
}Download the assembled general plan
/v1/governments/{id}/planEvery served general-plan document for a government, assembled into one markdown file. Some cities bind their plan into a single PDF and others split it across eight, so this normalises them — asking for "the general plan" does not require knowing which kind of city you have. Sections run in the order a plan is conventionally bound (Gov Code §65302), not alphabetically. Budgets are excluded.
Returns raw text/markdown, not the { data, meta } envelope — the point of the route is to hand you a file. It 404s when no plan documents are served. Page anchors survive as <!-- page N --> but are per section, numbering that section's own source PDF.
idThe government_id whose plan to assemble.
curl 'https://api.openpublica.com/v1/governments/alameda_county-california/plan'# General plan documents — alameda_county-california
Assembled by OpenPublica from the documents it serves for this
government. Each section below is a separate publication by the
government; page anchors (<!-- page N -->) refer to pages of that
section's own source PDF, linked in its heading.
**Contains 3 documents.**
OpenPublica has pinned these slots for this government: conservation,
ej, open_space. That is what we have looked for, not a statement that
the government publishes nothing else — a plan element absent here may
simply not have been reviewed yet. Last reviewed 2026-08-09.
---
## Conservation — Conservation Element
- Source: https://www.acgov.org/cda/planning/.../Conservation_Element.pdf
- Pages: 104
- Covers: conservation
- **Transcription findings were recorded for this document;** check
figures against the source.
<!-- page 1 -->
# CONSERVATION ELEMENT
## OF THE
# ALAMEDA COUNTY GENERAL PLANSearch document text
/v1/documents/searchWord search over page-cited chunks of currently-served documents. Each hit is an excerpt with the pages it came from, so it is citable on its own. text is a short passage around the match joined with …, not the whole page window — read it in context with the page route below.
This is word matching, not semantic search — unlike /v1/meetings/search there is no embedding behind it. Retired and unreadable documents are not indexed, so an empty result is not evidence the government published nothing; the listing route is what answers that.
qThe words to find.
government_idScope to one government. Omit to search every served document.
limitMax excerpts, 1–50 (default 10).
curl 'https://api.openpublica.com/v1/documents/search?q=housing+element&limit=2'{
"data": [
{
"document_id": "af906437578898f5447d3df23da1cf8d46607c548b98e2…",
"government_id": "miami_dade_county-florida",
"document_title": "III. Housing Element",
"doc_type": null,
"element": "housing",
"first_page": 1,
"last_page": 1,
"document_complete": true,
"source_url": "https://www.miamidade.gov/.../cdmp-housing-element.pdf",
"text": "# HOUSING ELEMENT\n\n## Introduction\n\nThe purpose of the
Housing Element is to provide a framework …",
"score": 2.127356038305101
}
],
"meta": { "count": 2, "limit": 2 }
}Retrieve a document
/v1/documents/{id}One document's metadata — a listing entry plus markdown_url. The listing omits that URL because it is a fifth of an entry, and reading pages is what the route below is for.
idThe document id, from a listing or search result.
curl 'https://api.openpublica.com/v1/documents/b5a2daeca5cc571e2b8867b6f77ac4ffe0c0802874e247b3688dcde9fda282c4'{
"data": {
"id": "b5a2daeca5cc571e2b8867b6f77ac4ffe0c0802874e247…",
"government_id": "alameda_county-california",
"title": "Conservation Element",
"status": "converted",
"covers": ["conservation"],
"source_url": "https://www.acgov.org/.../Conservation_Element_1994.pdf",
"verified_on": "2026-08-09",
"checked_at": "2026-08-16",
"page_count": 104,
"availability": {
"complete": false,
"problems": [
"5 footnote definition(s) never referenced (a marker may have been
merged into a number)"
],
"reason": "this document has transcription findings; any page that
could not be read is marked in place in the text"
},
"markdown_url": "https://openpublica.s3.us-west-2.amazonaws.com/….md"
},
"meta": {}
}Read document pages
/v1/documents/{id}/textThe markdown of one page range. Pages are transcribed from rendered pixels rather than the PDF text layer, so scanned tables come through as text, and a page that could not be transcribed appears as a marked hole rather than a silent omission.
Cite covered, not requested. Text is assembled from the page windows overlapping your range, so covered runs wider when a window overran the range and narrower when the character bound cut it short. The span is clamped to 40 pages and 120k characters rather than rejected — asking for a whole 300-page plan gives you the start of it, not a 400.
idThe document id to read.
first_pageFirst page of the range. Defaults to 1.
last_pageLast page. Defaults to first_page + 39, and is clamped to that span.
curl 'https://api.openpublica.com/v1/documents/b5a2daeca5cc571e2b8867b6f77ac4ffe0c0802874e247b3688dcde9fda282c4/text?first_page=1&last_page=2'{
"data": {
"document_id": "b5a2daeca5cc571e2b8867b6f77ac4ffe0c080…",
"government_id": "alameda_county-california",
"title": "Conservation Element",
"source_url": "https://www.acgov.org/.../Conservation_Element_1994.pdf",
"page_count": 104,
"requested": { "first_page": 1, "last_page": 2 },
"covered": { "first_page": 1, "last_page": 6 },
"markdown": "# CONSERVATION ELEMENT\n## OF THE\n# ALAMEDA COUNTY
GENERAL PLAN\n\n| | Volume |…"
},
"meta": { "max_page_span": 40 }
}List filter values
/v1/vocabularyReturns the values the category_tag and topic filters accept: meeting bodies mapped to their opaque tag UUIDs, and the most common topic names, each with counts. Read this before filtering — category_tags cannot be guessed. Without dates it covers a recent window, echoed as meta.default_window_days.
government_idScope to one government. Omit for the whole corpus.
government_idsComma-separated ids to scope to several governments.
start_dateEarliest meeting date, ISO YYYY-MM-DD.
end_dateLatest meeting date, ISO YYYY-MM-DD.
limitMax topics returned, 1–200. Defaults to 50.
curl 'https://api.openpublica.com/v1/vocabulary?government_id=sacramento_county-california'{
"data": {
"categories": [
{
"name": "Boards and Commissions",
"count": 10,
"tags": ["4d754a2b-3b8f-4706-9927-527fe66d0fb2"]
}
],
"topics": [
{ "topic": "Procedural", "count": 14 },
{ "topic": "Budget and Finance", "count": 11 }
]
},
"meta": { "total_meetings": 15, "default_window_days": 90, "limit": 50 }
}Retrieve coverage totals
/v1/statsReturns top-line counters for the whole archive — how many governments, states, and meetings Open Publica currently tracks. Takes no parameters.
Takes no parameters.
curl 'https://api.openpublica.com/v1/stats'{
"data": {
"total_governments": 103,
"total_states": 47,
"total_meetings": 5092
},
"meta": {}
}Put the whole archive on your AI's desk.
Point Claude, Cursor, or any MCP-capable assistant at our endpoint and it can search every meeting, pull exact transcript quotes, and compare cities — live, with no scraping, account, or key.
find_governments_by_nameResolve a city or state name to tracked governments.
find_governments_by_zipResolve a US ZIP code to nearby governments.
find_local_governmentsFind governments near a coordinate.
discover_meeting_vocabularyList the valid category and topic filter values.
search_meetings_semanticSearch all summaries — semantic, keyword, or hybrid.
list_recent_meetingsBrowse a government's meetings, newest first.
get_meetingFull summary, topics, and optionally the transcript.
search_meeting_transcriptPull exact quotes from one transcript, with timecodes.
get_government_infoProfile and details for one government.
get_government_statsActivity stats for a government or the whole corpus.
get_coverage_overviewCorpus totals — governments, states, meetings.
list_government_documentsA government’s adopted plan and budget documents, with its coverage state.
search_documentsWord search across plan and budget text, returning page-cited excerpts.
get_documentOne document’s metadata.
read_document_pagesRead a page range of a document as markdown.
https://api.openpublica.com/mcp{
"mcpServers": {
"openpublica": {
"url": "https://api.openpublica.com/mcp"
}
}
}In Claude web or desktop, add it under Settings → Connectors → Add custom connector.
Assembled plans are not an MCP tool. /plan returns a whole general plan — 27k to 179k tokens depending on the city — so it exists for download and offline analysis. The read path for a model is search_documents then read_document_pages, which is page-cited and bounded.
- Archival upload is deferred, so
video_urlis null until a meeting's recording lands on the Internet Archive, then backfilled. Fall back tosource_urlmeanwhile; summary, transcript, and thumbnail are always there. - Offered free for public-interest, research, and civic projects. Please cache responses and avoid hammering the endpoints.
- Data comes from AI transcription and summarization and may contain errors — the official record is authoritative.
- Shapes reflect current usage and may evolve. Build defensively and tolerate extra fields.
- Need a city covered, or a higher-volume use case? Reach out.