---
title: "Get Merkle inclusion proof"
method: GET
path: "/verify/{publicId}/proof"
tags: ["Verification"]
---

# Get Merkle inclusion proof

`GET /verify/{publicId}/proof`

## Request

- Base URL: `https://app.arkova.ai/api/v1`
- URL: `https://app.arkova.ai/api/v1/verify/{publicId}/proof`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-Key`
  - none

Returns the Merkle inclusion proof for a batch-anchored credential: the proof path, batch root, and the on-chain transaction it was committed in. `verified` is computed by locally recomputing the root from the proof — never trusted from stored status. Pass `?format=signed` to receive the bundle wrapped in a signed envelope bound to the issuer DID (requires PROOF_SIGNING_KEY_PEM/PROOF_SIGNING_KEY_ID to be configured; otherwise 503).

## Path parameters

- `publicId` string, required

## Query parameters

- `format` 'signed'

## Response `200`

Merkle inclusion proof

- object
  - `public_id` string
  - `fingerprint` string
  - `merkle_root` string, nullable
  - `merkle_proof` string[], nullable
  - `tx_id` string, nullable
  - `block_height` integer, nullable
  - `block_timestamp` string, date-time, nullable
  - `batch_id` string, nullable
  - `verified` boolean: Recomputed locally from the proof path — never trusted from stored anchor status.
  - `verdict` 'valid' | 'invalid' | 'unverifiable': R3: the same computation as `verified`, as three states. `invalid` means a check RAN and FAILED (an alarm; equivalent to verified=false). `unverifiable` means a check could not be completed — the duplicate-node structural guard was not exercised, either because the record carries no merkle_index/leaf_count or because the stored branch length does not match the tree its leaf_count describes — and is NOT an alarm. `valid` and `unverifiable` partition the old verified=true bucket; `verified` is unchanged and not deprecated.
  - `verdict_note` string: The measured / asserted / NOT-asserted statement for `verdict` (Constitution §1.5). Always accompanies `verdict`.
  - `proof_bundle` object, nullable: PROOF-05: self-contained bundle (block header, OP_RETURN payload, schema version, and — R1 — the tx_inclusion_branch + tx_block_index that let a verifier confirm transaction inclusion in the block locally) when the confirmation layer has been populated; null otherwise. The two R1 fields are additive and nullable (no schema-version bump) and are null on records populated before migration 0427.

## Other responses

- `400`: Invalid request
- `404`: Record not found, or no Merkle proof available (not batch-anchored)
- `429`: Rate limit exceeded
- `500`: Stored proof data is malformed, OR the proof is batch-linked but its exact leaf_count could not be determined (fail-closed: the CVE-2012-2459 structural guard cannot honestly run, so the request is not downgraded to a weaker verdict). Only the leaf_count body carries `verdict`.
- `503`: Signed-format requested but signing is not configured

---

[API](https://skmtc.dev/arkova/apis/arkova-verification-api.md) · [All operations](https://skmtc.dev/arkova/apis/arkova-verification-api/llms.txt) · [OpenAPI document](https://skmtc.dev/arkova/apis/arkova-verification-api/revisions/a14858d1efd4?raw)
