A read-only machine-readable mirror surface so other accountability platforms can replicate Goblin House's investigative archive. The site itself is a single point of failure; the federation API makes it possible to keep the corpus intact even if goblinhouse.net goes dark.
GET /api/v1/federation — capability indexGET /api/v1/federation/entities?since=<id>&limit=<n> — paginated entity catalogGET /api/v1/federation/sources?since=<id>&limit=<n> — paginated source list with content hashes for verifiabilityGET /api/v1/federation/facts?since=<id>&limit=<n> — paginated fact listGET /api/v1/federation/changes?since=<iso8601>&limit=<n> — unified changelog feed for incremental syncGET /attestation — daily Merkle-root attestation pageAll endpoints are public, no auth — the underlying data is already public on the HTML routes; this is a clean machine-readable mirror.
List endpoints use forward-only cursor pagination via a since parameter (numeric id or ISO date). The response includes a next link to keep walking.
Every list response carries an ETag. Clients sending If-None-Match get 304 Not Modified when nothing has changed since their last sync. Use this to throttle re-fetches.
Rate-limited at 120 requests/minute per IP via in-memory token bucket. Bursting is fine; sustained abuse degrades to 429 Retry-After.
Every source row carries a content_hash computed as sha256(coalesce(url, '<no-url>') || '\n' || raw_content).
Daily Merkle-root attestations roll up all source hashes into a single signed root — see /attestation for the latest and the per-day archive. A mirror can verify the corpus by recomputing the Merkle tree from its mirrored sources and comparing the root.
No key required. These public JSON surfaces are the fastest way to pull structured slices of the corpus:
GET /api/entities.json — the tracked-entity catalog (name, slug, type, role)GET /api/v2/health — federation API capability + statusGET /api/v2/dossier/<slug> — a single entity's full dossier (facts, sources, connections)For incremental full-corpus sync use the cursor-paginated /api/v1/federation/* endpoints above. This dataset is indexed by Google Dataset Search via the Dataset schema on this page.
Goblin House is an open public-records investigative platform. All data is sourced from government databases, SEC filings, FEC records, court filings, and other public registries.
Mirror and republish freely; please cite Goblin House when you publish derived findings. Send pull requests, corrections, or methodology feedback to [email protected].
curl -H 'Accept: application/json' \ -H 'If-None-Match: "<prev-etag>"' \ 'https://goblinhouse.net/api/v1/federation/entities?since=0&limit=100'
Response shape:
{
"ok": true,
"endpoint": "entities",
"since": 0,
"limit": 100,
"count": 100,
"next": "/api/v1/federation/entities?since=100&limit=100",
"rows": [
{
"id": 1,
"name": "Donald Trump",
"slug": "donald-trump",
"type": "elected_official",
"updated_at": "2026-05-25T18:32:41.182Z"
},
/* … */
],
"meta": {
"max_updated_at": "2026-05-25T18:32:41.182Z",
"row_count": 100
}
}
Headers: response carries ETag (revalidate on next pull); send back as If-None-Match to get 304 when nothing has changed. Cache-Control: public, max-age=300.
Mirror workflow: poll /api/v1/federation/changes?since=<your-last-iso8601> on a cadence (every 15 min is generous; every 6h is plenty for most mirrors), pull each changed entity/source/fact by id, and verify each source's hash against the daily Merkle root.