---
title: "Verify certificate"
method: POST
path: "/verify"
tags: ["Verification"]
---

# Verify certificate

`POST /verify`

## Request

- Base URL: `https://api.mnemom.ai/v1`
- URL: `https://api.mnemom.ai/v1/verify`
- Auth: none required

Verify an IntegrityCertificate. Performs Ed25519 signature verification, chain hash verification, Merkle inclusion proof verification, input commitment check, and optional STARK proof verification. Public endpoint, no authentication required.

## Request body

- object
  - `certificate` IntegrityCertificate, required: Machine-readable cryptographic certificate for an integrity checkpoint. Modeled on C2PA content credentials and W3C Verifiable Credentials.
    - `redacted` string[]: Present only when the caller is outside the agent's org: the listed fields (session_id, card_id, concerns, confidence, reasoning_summary, analysis_model, analysis_duration_ms, model_version) are blanked, emptied or omitted. No verifier reads them, so the certificate still verifies.
    - `@context` 'https://mnemom.ai/aip/v1', required: Namespace identifier
    - `type` 'IntegrityCertificate', required
    - `version` string, required: Certificate format version
    - `certificate_id` string, required: Unique certificate identifier (cert-{8 random chars})
    - `issued_at` string, date-time, required: ISO 8601 timestamp of certificate issuance
    - `subject` object, required: Identifies the checkpoint this certificate attests to
      - `checkpoint_id` string, required: Integrity checkpoint ID (ic-{uuid})
      - `agent_id` string, required
      - `session_id` string, required
      - `card_id` string, required
    - `claims` object, required: Analysis verdict and supporting evidence
      - `verdict` 'clear' | 'review_needed' | 'boundary_violation' | 'unverified' | 'unanalyzed'
      - `concerns` object[]
        - `category` string
        - `severity` string
        - `description` string
      - `confidence` number: Extraction confidence (0.0-1.0)
      - `reasoning_summary` string
      - `analysis_model` string
      - `analysis_duration_ms` number
    - `input_commitments` object, required: Cryptographic commitments to analysis inputs
      - `thinking_block_hash` string: SHA-256 hash of the thinking block
      - `card_hash` string: SHA-256 hash of the Alignment Card
      - `values_hash` string: SHA-256 hash of conscience values
      - `context_hash` string: SHA-256 hash of window context
      - `model_version` string
      - `combined_commitment` string: SHA-256 of all input fields concatenated
    - `proofs` object, required: Cryptographic evidence supporting the claims
      - `signature` object
        - `algorithm` 'Ed25519'
        - `key_id` string
        - `value` string: Base64-encoded Ed25519 signature
        - `signed_payload` string: Deterministic JSON string that was signed
      - `chain` object
        - `chain_hash` string
        - `prev_chain_hash` string, nullable
        - `position` integer
      - `merkle` object, nullable: Merkle inclusion proof. Null if not yet added to tree.
        - `leaf_hash` string
        - `leaf_index` integer
        - `root` string
        - `tree_size` integer
        - `inclusion_proof` object[]
          - `hash` string
          - `position` 'left' | 'right'
      - `verdict_derivation` object, nullable: SP1 STARK proof. Null if not yet proven.
        - `method` 'SP1-STARK'
        - `image_id` string: SP1 verifying-key hash of the guest program: 64 lowercase hex characters, no `0x` prefix. `GET /v1/checkpoints/{checkpoint_id}/certificate` returns this form. `POST /v1/verify` also accepts the legacy 132-character form (hex of `0x` plus the 64-character hash, beginning `3078`) found in certificates saved before MNE-8833. To convert it, hex-decode once and drop the leading `0x`.
        - `receipt` string: Base64-encoded STARK proof receipt
        - `journal` string: Base64-encoded public journal
        - `verified_at` string, date-time
    - `verification` object, required: URLs for independent verification
      - `keys_url` string, uri
      - `certificate_url` string, uri
      - `verify_url` string, uri

## Response `200`

Verification result

- VerifyCertificateResponse: Result of certificate verification
  - `valid` boolean, required: Whether all verification checks passed
  - `checks` object, required: Individual verification check results
    - `signature` object, required
      - `valid` boolean, required
      - `key_id` string: The signing key the certificate was verified against. Present when the certificate carries a key id; omitted otherwise (data-dependent).
    - `chain` object, required
      - `valid` boolean, required
      - `chain_hash` string, required
    - `merkle` object, nullable: Null if Merkle proof was not present in the certificate
      - `valid` boolean
      - `root` string
    - `input_commitment` object, required
      - `valid` boolean, required
      - `commitment` string, required
    - `verdict_derivation` object, nullable: Null if verdict derivation proof was not present
      - `valid` boolean
      - `method` string
  - `details` string, required: Semicolon-separated human-readable verification details

## Other responses

- `400`: Bad request
- `403`: Cross-origin write refused (`cross_origin_rejected`). A state-changing request that carries the browser session cookie must come from a first-party origin (`Origin`, or failing that `Referer`) and must not send a form-style body (text/plain, urlencoded, multipart) the operation does not declare. Bearer and API-key callers are never subject to this check.
- `404`: Resource not found
- `422`: Request was well-formed but semantically invalid (e.g., business-rule validation failure, malformed YAML inside a JSON payload).
- `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.
- `503`: An upstream dependency is currently unavailable. The request was not processed; retry after the cooldown window.

---

[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)
