# GET /v1/merkle/:artifactId
Source: https://docs.treeship.dev/api/merkle-proof

> Retrieve a self-contained Merkle inclusion proof for an artifact.

## Request

```
GET /v1/merkle/:artifactId
```

| Parameter     | Type   | Description                                    |
| ------------- | ------ | ---------------------------------------------- |
| `:artifactId` | string | The artifact ID (e.g., `art_f7e6d5c4b3a2f7e6`) |

No authentication required. Proofs are public so anyone can verify.

## Response

Returns a self-contained `ProofFile` JSON. This includes everything needed to verify that the artifact is included in a specific Merkle tree checkpoint -- no further requests to Hub required.

```json
{
  "artifact_id": "art_f7e6d5c4b3a2f7e6",
  "artifact_summary": {
    "actor": "agent://ci",
    "action": "test suite",
    "timestamp": "2026-03-28T14:30:00Z",
    "key_id": "ship_a1b2c3d4"
  },
  "inclusion_proof": {
    "leaf_index": 2048,
    "leaf_hash": "9d2fa1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0",
    "path": [
      { "direction": "Right", "hash": "1a2b3c4d..." },
      { "direction": "Left", "hash": "5e6f7a8b..." },
      { "direction": "Right", "hash": "9c0d1e2f..." }
    ],
    "algorithm": "sha256-rfc9162"
  },
  "checkpoint": {
    "index": 42,
    "root": "sha256:7e3a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0",
    "tree_size": 4096,
    "height": 12,
    "signed_at": "2026-03-28T15:00:00Z",
    "signer": "ship_a1b2c3d4",
    "public_key": "base64url-encoded-ed25519-public-key",
    "signature": "base64url-encoded-ed25519-signature",
    "algorithm": "sha256-rfc9162"
  }
}
```

### ProofFile fields

| Field                              | Type    | Description                                                                         |
| ---------------------------------- | ------- | ----------------------------------------------------------------------------------- |
| `artifact_id`                      | string  | The artifact this proof covers                                                      |
| `artifact_summary`                 | object  | Human-readable context about the artifact                                           |
| `artifact_summary.actor`           | string  | Actor URI that created the artifact                                                 |
| `artifact_summary.action`          | string  | Label describing the action                                                         |
| `artifact_summary.timestamp`       | string  | RFC 3339 timestamp of the artifact                                                  |
| `artifact_summary.key_id`          | string  | Key ID of the signer                                                                |
| `inclusion_proof`                  | object  | Merkle inclusion proof from leaf to root                                            |
| `inclusion_proof.leaf_index`       | integer | Position of the artifact in the tree                                                |
| `inclusion_proof.leaf_hash`        | string  | Hex-encoded SHA-256 hash of the artifact ID                                         |
| `inclusion_proof.path`             | array   | Sibling hashes forming the path from leaf to root                                   |
| `inclusion_proof.path[].direction` | string  | `Left` or `Right` -- position of the sibling relative to the current node           |
| `inclusion_proof.path[].hash`      | string  | Hex-encoded hash of the sibling node                                                |
| `inclusion_proof.algorithm`        | string  | Merkle algorithm: `sha256-rfc9162` (current) or `sha256-duplicate-last` (v1 legacy) |
| `checkpoint`                       | object  | Signed snapshot of the Merkle tree at proof time                                    |
| `checkpoint.index`                 | integer | Checkpoint sequence number                                                          |
| `checkpoint.root`                  | string  | Root hash in `sha256:<hex>` format                                                  |
| `checkpoint.tree_size`             | integer | Number of leaves in the tree                                                        |
| `checkpoint.height`                | integer | Tree height (ceil of log2 of tree\_size)                                            |
| `checkpoint.signed_at`             | string  | RFC 3339 timestamp of the checkpoint                                                |
| `checkpoint.signer`                | string  | Key ID of the checkpoint signer                                                     |
| `checkpoint.public_key`            | string  | Base64url-encoded Ed25519 public key                                                |
| `checkpoint.signature`             | string  | Base64url-encoded Ed25519 signature                                                 |
| `checkpoint.algorithm`             | string  | Merkle algorithm used to build the tree                                             |

## How to verify

The proof is self-contained. To verify locally:

1. Recompute the leaf hash: `sha256(artifact_id)` and compare to `inclusion_proof.leaf_hash`
2. Walk the `inclusion_proof.path` from leaf to root, combining hashes at each level based on `direction`
3. Compare the computed root against `checkpoint.root`
4. Verify the checkpoint signature using the embedded `public_key`

### CLI verification

```bash
treeship merkle verify proof.json
```

You can also fetch and verify in one step:

```bash
treeship merkle proof art_f7e6d5c4b3a2f7e6 --verify
```

## Errors

| Status | Body                               | Cause                             |
| ------ | ---------------------------------- | --------------------------------- |
| `400`  | `{"error": "missing artifact id"}` | No artifact ID in the URL path    |
| `404`  | `{"error": "proof not found"}`     | No proof exists for this artifact |

## Example

```bash
curl https://api.treeship.dev/v1/merkle/art_f7e6d5c4b3a2f7e6
```