Skip to content
Akashic
Find a destination
Release 2026-10-02 · 3,514 published places

Developers

The same published releases these pages read, answered by a machine surface: what it serves, how to reach it, what comes back, and how to pin a release so a figure you cite does not move under you. Everything on this page is read from the contract this build generates, so it cannot describe an API we do not serve.

What this API is

One surface, version 1.1.0, in two transports. 15 operations answer to an ordinary web request. 8 of those 15 are also reachable as tools, and a tool call is dispatched through the same operation the equivalent web request would have reached — so the scopes, the quota, the ordering, the paging and the error envelope are not a second implementation of themselves. The transport differs; nothing about the answers does.

It serves the same immutable releases these pages read. A figure you fetch here is the figure on the page, from the same publication, and both can be cited by the same release identifier.

How to reach it

The tool endpoint

POST/mcp

It answers on this site’s own address, so the endpoint above is the whole address. Messages are JSON over a single endpoint, with the protocol version 2025-06-18. The server calls itself akashic.

Methods it answers
initialize, notifications/initialized, tools/list, tools/call, ping. Anything else is answered as a method it does not have, which is how a client discovers that an optional capability is absent.
Largest result
1,024 KiB. A result above that is refused with the address that serves the bytes instead. It is never truncated — a truncated document is one that parses and is wrong.

The web addresses

The versioned operations below are served by the gateway at a path beginning /v1; the two liveness probes sit outside the version, at /health.

Those addresses are not reachable from this site yet. Available: the whole declared surface on this page, and the tool endpoint, which answers the same questions with the same schemas. Unavailable: every one of those addresses under this host: the route that carries API traffic here begins /api/v1, one segment away from the paths the gateway serves, so a request answers 404. As of . Coming back: the address is a deployment change, not a rebuild; the operations themselves are built.

Your first call

Ask what has been published. No account, no key, no sign-up: reading published reference data needs none of them, and that is a commitment rather than a convenience.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "list_releases", "arguments": { "limit": 1 } }
}

Post that to /mcp with a JSON content type. The reply summarizes one release: its identifier, when it was published, the licences behind it, how much it holds, and where its full list of files is, with the checksum to verify that list by. Take the identifier out of it — every later call can pin to it.

What it returns

Two body shapes and no third. Both carry the same metadata block, and you should read it before you use the figures.

{ "data": …, "meta": … }
One thing, under `data`, with the metadata that says where it came from.
{ "items": [ … ], "page": …, "meta": … }
A page of rows under `items`, with the cursor and ordering under `page`.

The same facts as headers

Every successful response repeats its metadata in headers, so a request that only asks for the headers tells you which publication your cached copy is current against without downloading the body — and a revalidation that comes back with no body still says which release it agreed with.

Response headers and the metadata field each one repeats
HeaderFieldWhat it says
x-akashic-releasereleaseIdThe immutable release this response came from.
x-akashic-freshnessfreshnesspublished, candidate, live or stale — the same value the body carries.
x-akashic-generated-atgeneratedAtWhen the payload was generated.
x-akashic-schema-versionschemaVersionThe version of the contract the payload is shaped by.
linkcitationUrlThe persistent address to cite this response by.

When it fails

A failure is one envelope with one code, over either transport. It names what happened and correlates to a request identifier; it never returns anything about our internals.

Error codes, their status and their meaning
CodeStatusMeaning
BAD_REQUEST400a parameter failed validation; details name the field
UNAUTHORIZED401the request needs an identity it did not present
FORBIDDEN403the identity is not allowed this resource or scope
NOT_FOUND404no resource matches the identifier at the requested release
RATE_LIMITED429quota exceeded; Retry-After states the horizon
INTERNAL_ERROR500an unexpected failure
SERVICE_NOT_CONFIGURED503the service is not ready to serve; Retry-After states the horizon

Identity and rate limits

Every operation this surface declares asks for public:read, which a caller presenting nothing already holds. So a key is never a precondition for reading published reference data, and a price of zero behind a login would still be a wall.

A key does two things and no others. It raises how many requests a minute you may make, and it carries permissions for material outside the free public corpus. Keys are issued from your account, shown once, and presented as Authorization: Bearer …. A key looks like ^ak_(live|test)_[A-Za-z0-9]{8,16}$ — it is bound to the environment that issued it, so a test key cannot read production by accident.

Rate plans

Rate plans, their ceiling and how a caller is identified
PlanCeilingCounted againstApplies to
anonymous60 requests a minuteclient_ipa caller presenting no credential
standard600 requests a minuteapi_key_idiam.api_key.rate_plan = 'standard' (the column default)

Over the ceiling, the answer says how long to wait rather than leaving you to guess. A tool call is one request and is metered exactly once — never twice, never free.

Permissions

A caller presenting nothing holds public:read. The rest exist for material that is not published reference data.

Permissions and what each one grants
PermissionGrants
public:readPublished reference data. Anonymous callers hold it implicitly.
releases:readRelease manifests and their artifacts metadata.
bulk:readRedirects to immutable bulk artifacts (API-007).
workspace:readA workspace the caller is a member of.
workspace:writeMutating a workspace the caller may write.
content:readUnpublished editorial content.
content:writeAuthoring editorial content.
content:publishPublishing editorial content.
jobs:readJob status.
jobs:writeSubmitting jobs.
live:operateLive operator actions.
adminInternal administration. Never held by a personal key at launch.

Bounds

A page is never larger than 100 rows, a query string never longer than 2,048 bytes, and a request that has not answered within 10 seconds is ended. Asking for more than the maximum is refused rather than quietly reduced, so you always know how much you got.

Pinning a release

Ask for nothing and you get the current stable release, which moves when a new one is published. Name a release and you get exactly that publication, for as long as the archive exists. A correction never edits a release: it publishes a new one that supersedes it, and the superseded release keeps its own address so a citation written against it still answers.

So a figure you quote does not move under you — provided you quote the release it came from. Every response names it, in the body and in a header, whether or not you asked.

12 of these 15 operations take a release directly: /v1/releases, /v1/releases/{releaseId}, /v1/releases/{releaseId}/artifacts, /v1/places/{placeId}, /v1/places/{placeId}/history, /v1/places/{placeId}/records, /v1/elections, /v1/elections/{electionId}/contests, /v1/contests/{contestId}, /v1/results, /v1/records/{recordType}, /v1/downloads/{artifactId}. The rest answer from the release the surface resolved for the call, and say which one that was.

Every operation

The whole declared surface, read from the contract this build generates. Nothing is omitted and nothing here is aspirational: what is declared and not built is in its own section below.

Every operation, with its address, what it answers, what it accepts and whether a tool reaches it
AddressWhat it answersAcceptsTool
GET /v1/releasesList published releases, newest first, as bounded summaries; each names the address, length and digest of its whole manifest.cursor, limit, releaseIdlist_releases
GET /v1/releases/{releaseId}One release's summary — identity, supersession, quality, counts, licences, bulk tables and citation — with the address, length and digest of its whole manifest.releaseId (required)none yet
GET /v1/releases/{releaseId}/artifactsOne release's artifacts, a page at a time, each with its role, length, digest and sources and the id getDownload answers for.releaseId (required), role, cursor, limitnone yet
GET /v1/places/{placeId}The Place View Model for one geography at one release.placeId (required), releaseIdget_place
GET /v1/places/{placeId}/historyThe Place's history series, one page at a time.placeId (required), cursor, limit, releaseIdnone yet
GET /v1/places/{placeId}/recordsThe records this Place holds, with universe, tie rule and method.placeId (required), cursor, limit, releaseIdnone yet
GET /v1/electionsElections in the published universe, one page at a time.jurisdictionId, year, cursor, limit, releaseIdnone yet
GET /v1/elections/{electionId}One election with the single contest this release can show for it — that contest's options, results, reporting, coverage and sources. Its whole ballot is at listContests.electionId (required)get_election
GET /v1/elections/{electionId}/contestsEvery contest on this election's ballot, one page at a time — including the contests whose results this release does not hold, each row saying which it is.electionId (required), cursor, limit, releaseIdlist_contests
GET /v1/contests/{contestId}One contest — options, results at the requested scope, reporting, coverage and sources.contestId (required), releaseIdget_contest_results
GET /v1/resultsResult facts at the canonical grain for one contest — the roll-up and every reporting unit beneath it, each row naming its unit — one page at a time.contestId (required), reportingUnitId, voteType, cursor, limit, releaseIdlist_results
GET /v1/records/{recordType}A record ranking of one type across the published universe.recordType (required), cursor, limit, releaseIdget_record
GET /v1/downloads/{artifactId}Metadata for, or a redirect to, an immutable bulk artifact (API-007).artifactId (required), releaseIdget_download
GET /health/liveLiveness — the process answers.No parameters.none yet
GET /health/readyReadiness — every declared dependency answers; 503 with the same shape otherwise.No parameters.none yet

The tools

Each tool binds to the operation that answers the same question and carries that operation’s response schema, from the same generator run. A tool that bound to nothing would be a tool with no schema to carry, and the generator refuses one.

Each tool, the operation it answers through, and what it requires
ToolAnswers throughWhat it answersRequires
get_place/v1/places/{placeId}The Place View Model for one geography at one release.placeId
get_election/v1/elections/{electionId}One election with the single contest this release can show for it — that contest's options, results, reporting, coverage and sources. Its whole ballot is at listContests.electionId
list_contests/v1/elections/{electionId}/contestsEvery contest on this election's ballot, one page at a time — including the contests whose results this release does not hold, each row saying which it is.electionId
get_contest_results/v1/contests/{contestId}One contest — options, results at the requested scope, reporting, coverage and sources.contestId
list_results/v1/resultsResult facts at the canonical grain for one contest — the roll-up and every reporting unit beneath it, each row naming its unit — one page at a time.contestId
get_record/v1/records/{recordType}A record ranking of one type across the published universe.recordType
list_releases/v1/releasesList published releases, newest first, as bounded summaries; each names the address, length and digest of its whole manifest.Nothing.
get_download/v1/downloads/{artifactId}Metadata for, or a redirect to, an immutable bulk artifact (API-007).artifactId

Deprecations and withdrawals

Nothing that was ever served has been taken away. What has left the declared surface is listed here anyway, because an absence decided on purpose still has to be announced like one.

get_citation — withdrawn
It was declared and never served, so no caller could have used it and there is no migration window to honour. Use the citation address on every response, and the download tool for an artifact’s full citation.

What is not built yet

These are declared and not built. They are listed so the inventory is complete, and written in the future tense because that is what they are — a page that described them as though they answered would cost you an afternoon.