Merkle Checkpoints
Retrieve and publish Merkle tree checkpoints. Checkpoints are signed snapshots of the append-only artifact tree.
Merkle checkpoints are a new addition. The endpoint is live but the response format may evolve before stabilizing.
Get a specific checkpoint
GET /v1/merkle/checkpoint/:id| Parameter | Type | Description |
|---|---|---|
:id | integer | The checkpoint ID (auto-incrementing integer, e.g., 42) |
No authentication required.
Get the latest checkpoint
GET /v1/merkle/checkpoint/latestAccepts an optional hub_id query parameter to scope the result to a specific hub connection.
GET /v1/merkle/checkpoint/latest?hub_id=hub_abc123Publish a checkpoint
POST /v1/merkle/checkpointRequires DPoP authentication. The CLI publishes a locally-signed checkpoint to Hub.
Request body
{
"root": "sha256:7e3a...",
"tree_size": 4096,
"height": 12,
"signed_at": "2026-03-25T10:00:00Z",
"signer": "ship_abc123",
"signature": "base64url-encoded-ed25519-signature",
"public_key": "base64url-encoded-public-key",
"rekor_index": 12345,
"index": 3
}| Field | Type | Required | Description |
|---|---|---|---|
root | string | Yes | SHA-256 root hash of the tree in sha256:<hex> format |
tree_size | integer | Yes | Number of leaves in the Merkle tree at this checkpoint |
height | integer | No | Height of the Merkle tree |
signed_at | string | Yes | RFC 3339 timestamp of when the checkpoint was signed |
signer | string | Yes | Key ID of the signer |
signature | string | Yes | Base64url-encoded Ed25519 signature of the canonical form |
public_key | string | Yes | Base64url-encoded public key bytes |
rekor_index | integer or null | No | Rekor transparency log index, if anchored |
index | integer | No | Checkpoint sequence number |
Publish response
{
"id": 42,
"root": "sha256:7e3a...",
"hub_received_at": "2026-03-25T10:00:01Z"
}GET response
Both GET endpoints return the same format -- the MerkleCheckpoint object stored by Hub:
{
"id": 42,
"root": "sha256:7e3a...",
"tree_size": 4096,
"height": 12,
"signed_at": "2026-03-25T10:00:00Z",
"signer": "ship_abc123",
"signature": "base64url-encoded-ed25519-signature",
"public_key": "base64url-encoded-public-key",
"rekor_index": 12345,
"hub_id": "hub_abc123"
}| Field | Type | Description |
|---|---|---|
id | integer | Auto-incrementing checkpoint ID |
root | string | SHA-256 root hash of the tree in sha256:<hex> format |
tree_size | integer | Number of leaves in the Merkle tree at this checkpoint |
height | integer | Height of the Merkle tree |
signed_at | string | RFC 3339 timestamp of when the checkpoint was signed |
signer | string | Key ID of the signer |
signature | string | Base64url-encoded Ed25519 signature over the canonical form |
public_key | string | Base64url-encoded public key bytes |
rekor_index | integer or null | Rekor transparency log index (null if not anchored) |
hub_id | string or null | Hub connection that published this checkpoint |
How checkpoints work
The CLI builds a local Merkle tree from all artifacts, signs a checkpoint over the root, and publishes it to Hub via POST /v1/merkle/checkpoint. The canonical form signed is: {index}|{root}|{tree_size}|{height}|{signer}|{signed_at}.
You can verify that:
- A checkpoint signature is valid using the included
public_key - The tree root matches the claimed tree size
- An artifact's Merkle proof resolves against a specific checkpoint's root
Errors
| Status | Body | Cause |
|---|---|---|
400 | {"error": "invalid checkpoint id"} | The :id parameter is not a valid integer |
400 | {"error": "missing required checkpoint fields"} | POST request is missing root, tree_size, signed_at, signer, signature, or public_key |
401 | DPoP error | POST request failed DPoP authentication |
404 | {"error": "checkpoint not found"} | No checkpoint with this ID |
404 | {"error": "no checkpoints found"} | No checkpoints have been created yet |
Examples
# Get a specific checkpoint by integer ID
curl https://api.treeship.dev/v1/merkle/checkpoint/42
# Get the latest checkpoint
curl https://api.treeship.dev/v1/merkle/checkpoint/latest
# Get the latest checkpoint for a specific hub connection
curl "https://api.treeship.dev/v1/merkle/checkpoint/latest?hub_id=hub_abc123"