API / version 1

Evidence in stable JSON.

The public API exposes the same timestamped observations as the website. It is read-only and needs no key or account.

Requests and caching

Every response is application/json and carries Cache-Control: public, s-maxage=60, stale-while-revalidate=300. Honouring that header costs you nothing and keeps the index cheap to serve, so please read from your cache rather than polling. Only GET and HEAD are served; any other method returns 405 with an Allow header.

Errors never return a bare status. The body is always an object with a code that is safe to branch on and a message written for a person:

{ "error": { "code": "invalid_limit", "message": "limit must be an integer from 1 to 100" } }

List servers

GET /api/v1/servers
q
Free text matched against the title, registry name, and description.
state
One of verified, stale, broken, auth_required, or unverifiable.
package
The package registry type: npm, pypi, or oci.
transport
The transport declared by the Registry record, for example stdio.
client
A client slug, as listed on Clients — for example claude-code.
limit
An integer from 1 to 100. Defaults to 25. A value outside that range is refused rather than clamped, so a client is never handed a different number of rows than it asked for without being told.
cursor
The nextCursor from the previous response. Omit it for the first page; it is null on the last.
GET /api/v1/servers?state=verified&package=npm&limit=2

{
  "data": [
    {
      "id": "srv_01J…",
      "registryName": "example/one",
      "title": "Example Server",
      "description": "What the server says it does.",
      "state": "verified",
      "observedAt": "2026-09-15T00:00:00.000Z",
      "toolCount": 3,
      "url": "/servers/example/one"
    }
  ],
  "nextCursor": null
}

Server detail

GET /api/v1/servers/:namespace/:name

Returns the Registry metadata, the runnable packages, and the public observation history for one server, under data. Each run in that history names the exact package version it tested, which is usually not the version published today. An unknown pair returns 404 with the code not_found.

Verification run

GET /api/v1/verification-runs/:id

One observation, by its identifier. A run that has not cleared the confirmation rule is absent here and returns 404 with the code not_found — the same answer as a run that never existed, because any difference between the two would disclose a failure the rule exists to withhold.

Dataset statistics

GET /api/v1/stats
{ "data": { "indexedServers": 979, "verifiedServers": 0, "observedAt": null } }

Error codes

invalid_limit
400 — the limit was not an integer from 1 to 100.
invalid_cursor
400 — the cursor is malformed, or was made against a different sort order. Start again from the first page.
not_found
404 — no such server, or no publishable run with that identifier.
method_not_allowed
405 — the API is read-only. The response names the methods that are served.

What is not exposed

Internal stderr, worker leases, and pending confirmation details are never published, and a state always carries the timestamp of the observation it describes rather than the time you asked for it.