Beacon API
The authenticated programmatic beacon surfaces - JSON:API endpoints under /api/json/beacons (list, latest, by id, by hash), the GraphQL beacons/latestBeacon/beacon/beaconByHash queries, the four-field beacon object, error and rate-limit behavior, and beacon proof generation by block id.
Overview
Truestamp beacons are read-only projections of finalized or committed blocks, exposed as verifiable public randomness and proof-of-life markers. Anyone can browse them without an account on the public beacon page; this concept is the reference for the programmatic surfaces, which all require an authenticated caller. Machine consumers (CLI implementers, monitoring jobs, downstream verifiers) read beacons over four JSON:API endpoints under /api/json/beacons, four equivalent GraphQL queries, the MCP server’s code mode, or a real-time console stream. Every surface returns the same four-field beacon object: id, hash, timestamp, and previous_hash.
Authentication and rate limits
The beacon endpoints sit on Truestamp’s standard authenticated API surfaces, so the credential rules are the same as the rest of the JSON:API and GraphQL:
Authorization: Bearer <api-key-or-oauth-access-token>
- An API key works on both surfaces with no scope restrictions.
- An OAuth 2.1 access token needs the
api:readscope; every beacon operation is a read. - A missing, blank, or invalid credential is rejected with
401 Unauthorized.
Requests are rate limited per authenticated caller on each surface (by default 120 requests per minute each for JSON:API and GraphQL). Exceeding the budget returns 429 Too Many Requests with a machine-readable error body. A polling consumer should treat the roughly once-a-minute block cadence as the natural refresh rate; polling faster than that yields no new data.
The beacon object
A beacon exposes exactly four fields, projected from the underlying block:
| Field | Type | Meaning |
|---|---|---|
id |
UUIDv7 string | The underlying block’s identifier, usable for follow-up lookups and proof generation. |
hash |
64-char lowercase hex | The block hash, a SHA-256 digest. This is the beacon value. |
timestamp |
ISO 8601 UTC | When the underlying block was finalized. |
previous_hash |
64-char lowercase hex | Chain-link to the previous beacon’s hash, so a consumer can walk the chain. |
Only finalized or committed blocks ever surface as beacons. Block internals such as the Merkle root, state, signature, and signing-key material are deliberately not part of the beacon shape; a consumer who needs them can fetch the full block from GET /api/json/blocks/:id using the beacon’s id. Field names are snake_case on JSON:API and the console stream, and camelCase (previousHash) on GraphQL.
JSON:API beacon responses are plain JSON, not JSON:API resource envelopes: the list endpoint returns a bare JSON array of beacon objects, and the single-beacon endpoints return a bare beacon object.
JSON:API endpoints
All four routes are GET requests under /api/json/beacons:
| Path | Returns |
|---|---|
/api/json/beacons |
The latest beacons, newest first. ?limit= selects 1 to 100; default 25. |
/api/json/beacons/latest |
The current head beacon. |
/api/json/beacons/:id |
One beacon by block id (UUIDv7). |
/api/json/beacons/by-hash/:hash |
One beacon by block hash (64 hex characters; matching is case-insensitive). |
A single beacon response looks like:
{
"id": "019db702-b08c-73dc-a7cd-2c5e011f1dad",
"hash": "ffe86dc05a0c7b42279f7fa6afb016cd6928980d24673051fc58731492ce2a1b",
"timestamp": "2026-04-22T21:05:00Z",
"previous_hash": "1c4812bdfec2bf29333136d86bc996f866e38177acc90565a0554c7ec698029b"
}
Lookup notes:
- The
:idlookup validates the id as a UUIDv7 before querying; a malformed id is a400, an unknown id is a404. A block that exists but is not yet finalized or committed is also a404(it is not a beacon yet). - The
by-hashlookup validates the value as a SHA-256 hex string; uppercase input is accepted and downcased before matching. A malformed value is a400, a miss is a404. latestreturns anullbody (with200) only in the edge case where the chain has no finalized block yet; on any initialized deployment a head beacon always exists.
GraphQL queries
The same four reads are available at the /gql endpoint as queries, with camelCase field names:
query ListBeacons {
beacons { id hash timestamp previousHash }
}
query LatestBeacon {
latestBeacon { id hash timestamp previousHash }
}
query BeaconById($id: String!) {
beacon(id: $id) { id hash timestamp previousHash }
}
query BeaconByHash($hash: String!) {
beaconByHash(hash: $hash) { id hash timestamp previousHash }
}
The beacons list returns the most recent beacons, newest first (up to 25). Lookup misses and invalid arguments surface in the standard GraphQL errors envelope rather than as HTTP error statuses. The interactive playground described in the GraphQL concept is the quickest way to explore these queries live.
Errors
Error behavior on the JSON:API surface:
| Status | Cause |
|---|---|
401 |
Missing, blank, malformed, or invalid bearer credential. |
400 |
Malformed :id (not a UUIDv7) or malformed :hash (not 64 hex characters), or an out-of-range ?limit=. |
404 |
No matching beacon: unknown id or hash, or a block that exists but is not yet finalized or committed. |
429 |
Per-caller rate limit exceeded; slow down and retry shortly. |
Error bodies are JSON with an errors array. On GraphQL, the equivalent failures arrive as entries in the response’s errors list with a null data field.
Beacon proofs over the API
A beacon’s existence and its commitment to a public blockchain can be proven with a downloadable proof bundle, generated programmatically from the beacon’s id:
curl -s -X POST https://www.truestamp.com/api/json/proof/generate \
-H "Authorization: Bearer $TRUESTAMP_API_KEY" \
-H "Content-Type: application/vnd.api+json" \
-d '{"data": {"id": "<beacon-id>", "type": "beacon"}}'
typeis required and has no auto-detection."beacon"produces the beacon-flavored bundle (top-level type code11);"block"produces the plain block bundle (type code10) for the same block. The two are structurally identical but cryptographically distinct, because the type code is bound into the signed payload.- An optional
formatargument selects"json"(default) or"cbor"(base64-encoded CBOR binary). - Proof generation requires the block to have at least one commitment on a public blockchain. A freshly finalized beacon sits in a brief window before the next epoch commit during which no proof can be generated yet.
- Unlike the beacon reads, the proof routes wrap their response in a
{"result": ...}envelope.
The companion POST /api/json/proof/verify accepts a proof bundle plus optional type (assert the expected subject type), expected_hash, and skip_external (skip live Stellar and Bitcoin checks for offline or bounded-latency verification) arguments. The bundle’s wire format is specified in the proof bundle format, and the end-to-end procedure in how to verify a proof.
Other authenticated surfaces
Two more authenticated surfaces expose the same beacon reads:
- MCP code mode. The MCP server’s Lua manifest whitelists the same four beacon reads (list, get, latest, get by hash), so an agent can compose beacon lookups with other calls in a single script. Use the server’s Lua API docs tool to discover the exact call shapes.
- Console WebSocket. The developer console channel offers a global
beaconsstream that pushes abeacon.createdevent, carrying the same four fields, each time a new block is finalized. This is the push-based alternative to pollinglatest.
Examples
Fetch the current head beacon:
curl -s https://www.truestamp.com/api/json/beacons/latest \
-H "Authorization: Bearer $TRUESTAMP_API_KEY" | jq
List the ten most recent beacons:
curl -s "https://www.truestamp.com/api/json/beacons?limit=10" \
-H "Authorization: Bearer $TRUESTAMP_API_KEY" | jq
Look up a beacon by its hash:
curl -s https://www.truestamp.com/api/json/beacons/by-hash/<64-hex-hash> \
-H "Authorization: Bearer $TRUESTAMP_API_KEY" | jq
The same head lookup over GraphQL:
curl -s -X POST https://www.truestamp.com/gql \
-H "Authorization: Bearer $TRUESTAMP_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "{ latestBeacon { id hash timestamp previousHash } }"}'
A consumer walking the chain follows previous_hash from any beacon through repeated by-hash lookups until it reaches the first block, whose previous_hash is a fixed sentinel value rather than a real predecessor.