---
title: Merkle Checkpoints
description: Retrieve and publish Merkle tree checkpoints. Checkpoints are signed snapshots of the append-only artifact tree.
---

import { Callout } from 'fumadocs-ui/components/callout';

<Callout type="warn">
Merkle checkpoints are a new addition. The endpoint is live but the response format may evolve before stabilizing.
</Callout>

## 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/latest
```

Accepts an optional `hub_id` query parameter to scope the result to a specific hub connection.

```
GET /v1/merkle/checkpoint/latest?hub_id=hub_abc123
```

## Publish a checkpoint

```
POST /v1/merkle/checkpoint
```

Requires DPoP authentication. The CLI publishes a locally-signed checkpoint to Hub.

### Request body

```json
{
  "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

```json
{
  "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:

```json
{
  "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:
1. A checkpoint signature is valid using the included `public_key`
2. The tree root matches the claimed tree size
3. 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

```bash
# 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"
```
