---
title: "Verify on-chain proof"
method: GET
path: "/on-chain/verify-proof/{agent_id}"
tags: ["On-Chain"]
---

# Verify on-chain proof

`GET /on-chain/verify-proof/{agent_id}`

## Request

- Base URL: `https://api.mnemom.ai/v1`
- URL: `https://api.mnemom.ai/v1/on-chain/verify-proof/{agent_id}`
- Auth: none required

Verify an agent's Merkle commitment. The agent's stored root is **recomputed from its stored leaf hashes**, the stored `leaf_count` is checked against the actual number of leaves, and — when `leaf_index` is supplied — a real inclusion proof for that leaf is generated and verified against the recomputed root and returned so the caller can re-derive it independently. The confirming anchor is then looked up by the **recomputed** root, so an anchor row can never vouch for a root nobody can rebuild.

**Scope limit, stated rather than hidden:** the anchored root is read from Mnemom's own anchor record, not from a Base RPC call. A `verified: true` therefore means "this tree is internally consistent and matches the root we recorded as anchored" — it does not by itself prove the chain agrees. `verification.anchored_root_source` reports this.

## Path parameters

- `agent_id` string, required

## Query parameters

- `leaf_index` integer

## Response `200`

Proof verification result. `verified: true` requires ALL of: the root recomputes from the stored leaf hashes, `leaf_count` agrees with the leaf array, any requested inclusion proof verifies, and a `confirmed` anchor exists for the recomputed root. Any failed step returns `verified: false` with a `reason` — never a bare true. (handleVerifyProof in src/on-chain/handlers.ts.)

- object
  - `verified` boolean, required: True only when the agent's root was successfully recomputed from its stored leaves AND a confirmed on-chain anchor exists for that recomputed root (and, if `leaf_index` was supplied, its inclusion proof verified).
  - `agent_id` string, required
  - `reason` 'no_merkle_tree' | 'no_checkpoint' | 'no_leaf_hashes' | 'root_mismatch' | 'leaf_count_mismatch' | 'leaf_index_out_of_range' | 'inclusion_proof_failed' | 'not_anchored': Present only when `verified` is false. `no_merkle_tree`: the agent has no merkle tree row; `no_checkpoint`: the tree has no merkle_root yet; `no_leaf_hashes`: a root is stored but no leaves are, so it cannot be rebuilt; `root_mismatch`: the root recomputed from the stored leaves does not equal the stored root (tampering or corruption); `leaf_count_mismatch`: the stored leaf_count disagrees with the number of stored leaves (silent truncation); `leaf_index_out_of_range`: the requested leaf_index exceeds the tree; `inclusion_proof_failed`: the proof for the requested leaf does not reconstruct the root; `not_anchored`: the tree verifies but has no confirmed anchor.
  - `merkle_root` string: The agent's stored Merkle root. Present when a checkpoint exists (i.e. absent for the `no_merkle_tree`/`no_checkpoint` cases).
  - `recomputed_root` string: The root recomputed from the stored leaf hashes. Returned only on `root_mismatch`, so the discrepancy is inspectable.
  - `leaf_count` integer: Leaf count, included on the `leaf_count_mismatch` and `leaf_index_out_of_range` failures for diagnosis.
  - `leaf_hashes_length` integer: Actual number of stored leaf hashes. Returned only on `leaf_count_mismatch`.
  - `inclusion_proof` object, nullable: The verified inclusion proof for the requested leaf. Null when `leaf_index` was not supplied. The caller can recompute the root from `leaf_hash` plus the sibling path without trusting this endpoint.
    - `leaf_hash` string
    - `leaf_index` integer
    - `tree_size` integer
    - `siblings` object[]
      - `hash` string
      - `position` 'left' | 'right'
  - `verification` object: What was actually checked, so a caller never has to infer it from `verified` alone.
    - `root_recomputed_from_leaves` boolean: True when the stored root was successfully rebuilt from the stored leaves.
    - `leaf_count` integer
    - `leaf_count_checked` boolean: Whether the stored `leaf_count` was available to compare against the leaf array. False when the row carries no usable count, in which case the silent-truncation check could not run — reported rather than skipped silently.
    - `inclusion_proof_verified` boolean, nullable: True when a requested inclusion proof verified; null when no `leaf_index` was supplied (not checked, as distinct from checked-and-failed).
    - `anchored_root_source` 'mnemom_database' | 'null', nullable: Where the anchored root was read from. `mnemom_database` means Mnemom's own anchor record, NOT a Base RPC read — the residual trust assumption, disclosed rather than hidden. Null when no confirmed anchor was found.
  - `anchor` object: The confirming anchor. Present only when `verified` is true.
    - `tx_hash` string, nullable
    - `block_number` integer, nullable
    - `chain` 'base-sepolia' | 'base'
    - `anchored_at` string, date-time

## Other responses

- `400`: Bad request
- `401`: Authentication required
- `403`: Forbidden
- `404`: Resource not found
- `429`: Rate-limit exceeded. The global per-IP limiter (100 requests/minute, applied to every `/v1/*` route) rejected this request. Back off until the window resets — `Retry-After` carries the cooldown in seconds and `X-RateLimit-Reset` the absolute reset time.
- `500`: Server error — request was well-formed but the server failed to fulfill it. Typically a downstream dependency (DB / RPC / external API) returned an unexpected error.

---

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