> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mnemom.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrity Certificates

> Machine-readable cryptographic certificates that bundle all verification evidence for an integrity checkpoint into a single, self-describing document.

An **IntegrityCertificate** is a machine-readable cryptographic document that bundles all verification evidence for a single integrity checkpoint. It is modeled on [C2PA content credentials](https://c2pa.org/) and [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model-2.0/), adapted for AI agent integrity attestation.

Certificates are self-describing: they contain the verdict, the cryptographic proofs, and the URLs needed to verify them. Any party can independently verify a certificate without trusting the Mnemom API.

***

## Certificate schema

An IntegrityCertificate has four top-level sections: **subject**, **claims**, **input\_commitments**, and **proofs**.

### Envelope fields

| Field | Type | Description |
| - | - | - |
| `@context` | `string` | Always `"https://mnemom.ai/aip/v1"`. Namespace identifier. |
| `type` | `string` | Always `"IntegrityCertificate"`. |
| `version` | `string` | Certificate format version. Currently `"1.0.0"`. |
| `certificate_id` | `string` | Unique identifier in the format `cert-{8 random chars}`. |
| `issued_at` | `string` | ISO 8601 timestamp of certificate issuance. |

### Subject

Identifies the integrity checkpoint this certificate attests to.

| Field | Type | Description |
| - | - | - |
| `checkpoint_id` | `string` | The integrity checkpoint ID (`ic-{uuid}` format). |
| `agent_id` | `string` | The agent that produced the thinking block. |
| `session_id` | `string` | The session in which the checkpoint was created. |
| `card_id` | `string` | The Alignment Card used for analysis. |

### Claims

The analysis verdict and supporting evidence.

| Field | Type | Description |
| - | - | - |
| `verdict` | `string` | One of `clear`, `review_needed`, `boundary_violation`. |
| `concerns` | `array` | Array of concern objects, each with `category`, `severity`, and `description`. |
| `confidence` | `number` | Extraction confidence (0.0-1.0). Reflects provider adapter reliability. |
| `reasoning_summary` | `string` | Human-readable summary of the analysis reasoning. |
| `analysis_model` | `string` | The LLM model used for analysis (e.g., `"claude-sonnet-4-20250514"`). |
| `analysis_duration_ms` | `number` | Wall-clock time for the analysis in milliseconds. |

### Input commitments

Cryptographic commitments to the inputs used for analysis. These enable verification that the analysis was performed over the claimed inputs without revealing the inputs themselves.

| Field | Type | Description |
| - | - | - |
| `thinking_block_hash` | `string` | SHA-256 hash of the thinking block content. |
| `card_hash` | `string` | SHA-256 hash of the Alignment Card (deterministic JSON). |
| `values_hash` | `string` | SHA-256 hash of the conscience values array. |
| `context_hash` | `string` | SHA-256 hash of the window context. |
| `model_version` | `string` | Analysis model version identifier. |
| `combined_commitment` | `string` | SHA-256 of all fields concatenated with `\|` separator. |

### Proofs

Cryptographic evidence supporting the claims. Contains four proof types.

#### `proofs.signature`

Ed25519 digital signature over the signed payload.

| Field | Type | Description |
| - | - | - |
| `algorithm` | `string` | Always `"Ed25519"`. |
| `key_id` | `string` | Identifier of the signing key. Resolvable via `GET /v1/keys`. |
| `value` | `string` | Base64-encoded Ed25519 signature. |
| `signed_payload` | `string` | The exact JSON string that was signed (deterministic, sorted keys). |

#### `proofs.chain`

Hash chain linking this checkpoint to its predecessor in the session.

| Field | Type | Description |
| - | - | - |
| `chain_hash` | `string` | SHA-256 hash of the chain link (includes previous hash, checkpoint ID, verdict, thinking block hash, input commitment, and timestamp). |
| `prev_chain_hash` | `string \| null` | Previous chain hash. `null` for the first checkpoint in a session. |
| `position` | `number` | Zero-indexed position in the session chain. |

#### `proofs.merkle`

Merkle tree inclusion proof. May be `null` if the checkpoint has not yet been added to the agent's Merkle tree.

| Field | Type | Description |
| - | - | - |
| `leaf_hash` | `string` | SHA-256 leaf hash of this checkpoint in the Merkle tree. |
| `leaf_index` | `number` | Index of this leaf in the tree. |
| `root` | `string` | Current Merkle root. |
| `tree_size` | `number` | Total number of leaves in the tree. |
| `inclusion_proof` | `array` | Array of sibling hashes, each with `hash` (hex) and `position` (`"left"` or `"right"`). |

#### `proofs.verdict_derivation`

Zero-knowledge proof of correct verdict derivation. May be `null` if no ZK proof has been generated. See [Verifiable Verdicts](/protocols/aip/verifiable-verdicts) for details.

| Field | Type | Description |
| - | - | - |
| `method` | `string` | `"SP1-STARK"` for proofs generated by the current prover. `"RISC-Zero-STARK"` is also a valid value, accepted for certificates issued before the SP1 migration. |
| `image_id` | `string` | The guest program image ID. |
| `receipt` | `string` | The STARK proof receipt (base64). |
| `journal` | `string` | The public journal output (base64). |
| `verified_at` | `string` | ISO 8601 timestamp of when the proof was verified. |

### Verification URLs

Self-contained links for independent verification.

| Field | Type | Description |
| - | - | - |
| `verification.keys_url` | `string` | URL to fetch signing keys: `https://api.mnemom.ai/v1/keys` |
| `verification.certificate_url` | `string` | URL to retrieve this certificate. |
| `verification.verify_url` | `string` | URL to submit this certificate for server-side verification: `https://api.mnemom.ai/v1/verify` |

### Public and member views

`GET /v1/checkpoints/{checkpoint_id}/certificate` needs no authentication, but what it returns depends on who asks:

* **Members of the agent's org** get the full certificate described above.
* **Everyone else** (anonymous callers, or signed-in users outside the org) gets a verify-only view. It keeps the envelope fields, `subject.checkpoint_id`, `subject.agent_id`, `claims.verdict`, the `input_commitments` hashes, `proofs`, and `verification`. The session ID, card ID, concerns, confidence, reasoning summary, analysis model and duration, and `input_commitments.model_version` are blanked or omitted, and an extra top-level `redacted` array names each withheld field (for example `"subject.session_id"` or `"claims.concerns"`).

None of the withheld fields is covered by a signature, chain, or Merkle proof, so a verify-only certificate passes every verification step below exactly as the full certificate does.

***

## Signed payload format

The `signed_payload` field contains the exact JSON string that the Ed25519 signature covers. It is constructed with **deterministic key ordering** (alphabetically sorted) to ensure the same payload produces the same bytes regardless of property insertion order.

The signed payload includes these fields, sorted alphabetically:

```json theme={null}
{
  "agent_id": "agent-abc123",
  "chain_hash": "a1b2c3...",
  "checkpoint_id": "ic-550e8400-e29b-41d4-a716-446655440000",
  "input_commitment": "d4e5f6...",
  "thinking_block_hash": "7a8b9c...",
  "timestamp": "2026-02-18T12:00:00.000Z",
  "verdict": "clear"
}
```

The JSON is produced using `JSON.stringify(payload, Object.keys(payload).sort())`, which ensures keys appear in lexicographic order. This exact string (UTF-8 encoded) is the message passed to `Ed25519.sign()`.

***

## Input commitment computation

The `combined_commitment` is computed as follows:

1. Each input field is serialized to JSON with **recursively sorted keys** (deterministic stringify).
2. The serialized fields are concatenated with a pipe (`|`) separator in this order:
   * Card (full Alignment Card object)
   * Conscience values array
   * Window context array
   * Model version string
   * Prompt template version string
3. The concatenated string is UTF-8 encoded and hashed with **SHA-256**.
4. The result is the hex-encoded hash.

```
combined_commitment = SHA-256(
  deterministicJSON(card) + "|" +
  deterministicJSON(conscience_values) + "|" +
  deterministicJSON(window_context) + "|" +
  deterministicJSON(model_version) + "|" +
  deterministicJSON(prompt_template_version)
)
```

This commitment proves the analysis was performed over specific inputs without revealing the inputs. A verifier who has the original inputs can recompute the commitment and compare.

***

## Verification instructions

Any party can verify an IntegrityCertificate using the following five steps. Steps 1-4 can be performed offline with the certificate and the public key. Step 5 requires a network call to the prover service.

### Step 1: Fetch the public key

Retrieve the signing key referenced by `proofs.signature.key_id`:

```bash theme={null}
curl https://api.mnemom.ai/v1/keys
```

Find the key entry matching `key_id`. The `public_key` field is the hex-encoded Ed25519 public key.

<Note>
  Public keys can be cached. They rotate infrequently, and the `is_active` field indicates whether a key is currently in use for new signatures.
</Note>

### Step 2: Verify the Ed25519 signature

Verify `proofs.signature.value` (base64-encoded) against `proofs.signature.signed_payload` (UTF-8 string) using the public key from Step 1.

```javascript theme={null}
import * as ed from '@noble/ed25519';

const publicKey = hexToBytes(keyEntry.public_key);
const signature = base64ToBytes(cert.proofs.signature.value);
const message = new TextEncoder().encode(cert.proofs.signature.signed_payload);

const valid = await ed.verifyAsync(signature, message, publicKey);
```

If the signature is invalid, the certificate has been tampered with. Reject it.

### Step 3: Recompute and verify the chain hash

Recompute the chain hash from the certificate fields and compare to `proofs.chain.chain_hash`:

```
preimage = (prev_chain_hash || "genesis") + "|" +
           checkpoint_id + "|" +
           verdict + "|" +
           thinking_block_hash + "|" +
           combined_commitment + "|" +
           issued_at

expected = SHA-256(preimage)
```

If `expected !== proofs.chain.chain_hash`, the chain link has been altered.

### Step 4: Walk the Merkle inclusion proof

If `proofs.merkle` is present, verify that the checkpoint is included in the agent's Merkle tree:

1. Start with `current = proofs.merkle.leaf_hash`.
2. For each sibling in `proofs.merkle.inclusion_proof`:
   * If `position === "left"`: `current = SHA-256(sibling.hash + current)`
   * If `position === "right"`: `current = SHA-256(current + sibling.hash)`
3. Compare `current` to `proofs.merkle.root`.

If they match, the checkpoint is included in the tree. Members of the agent's org can also cross-reference the root against the agent's current Merkle root via [`GET /v1/agents/{agent_id}/merkle-root`](/api-reference/endpoint/get-agents-id-merkle-root) (authenticated; anonymous requests get `401`).

### Step 5: Verify the STARK proof (optional)

If `proofs.verdict_derivation` is present, the verdict was proven via an SP1 STARK proof. Verification can be performed:

* **Via the API**: Submit the certificate to [`POST /v1/verify`](/api-reference/endpoint/post-verify). The API will delegate STARK verification to the prover service.
* **Locally**: Use the SP1 verifier with the `image_id` and `receipt` from the certificate. See [Verifiable Verdicts](/protocols/aip/verifiable-verdicts) for details.

***

## Example certificate

```json theme={null}
{
  "@context": "https://mnemom.ai/aip/v1",
  "type": "IntegrityCertificate",
  "version": "1.0.0",
  "certificate_id": "cert-k7m2x9pq",
  "issued_at": "2026-02-18T14:30:00.000Z",

  "subject": {
    "checkpoint_id": "ic-550e8400-e29b-41d4-a716-446655440000",
    "agent_id": "agent-abc123",
    "session_id": "sess-def456",
    "card_id": "card-ghi789"
  },

  "claims": {
    "verdict": "clear",
    "concerns": [],
    "confidence": 1.0,
    "reasoning_summary": "Agent reasoning is consistent with declared values. No boundary violations detected.",
    "analysis_model": "claude-sonnet-4-20250514",
    "analysis_duration_ms": 1847
  },

  "input_commitments": {
    "thinking_block_hash": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2",
    "card_hash": "f1e2d3c4b5a6f1e2d3c4b5a6f1e2d3c4b5a6f1e2d3c4b5a6f1e2d3c4b5a6f1e2",
    "values_hash": "1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b",
    "context_hash": "e3d2c1b0a9f8e3d2c1b0a9f8e3d2c1b0a9f8e3d2c1b0a9f8e3d2c1b0a9f8e3d2",
    "model_version": "claude-sonnet-4-20250514",
    "combined_commitment": "4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e6f1a2b3c4d5e"
  },

  "proofs": {
    "signature": {
      "algorithm": "Ed25519",
      "key_id": "key-primary-2026",
      "value": "MEUCIQD...base64...==",
      "signed_payload": "{\"agent_id\":\"agent-abc123\",\"chain_hash\":\"...\",\"checkpoint_id\":\"ic-550e8400-e29b-41d4-a716-446655440000\",\"input_commitment\":\"...\",\"thinking_block_hash\":\"...\",\"timestamp\":\"2026-02-18T14:30:00.000Z\",\"verdict\":\"clear\"}"
    },
    "chain": {
      "chain_hash": "b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3",
      "prev_chain_hash": null,
      "position": 0
    },
    "merkle": {
      "leaf_hash": "c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
      "leaf_index": 0,
      "root": "d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5",
      "tree_size": 1,
      "inclusion_proof": []
    },
    "verdict_derivation": null
  },

  "verification": {
    "keys_url": "https://api.mnemom.ai/v1/keys",
    "certificate_url": "https://api.mnemom.ai/v1/checkpoints/ic-550e8400-e29b-41d4-a716-446655440000/certificate",
    "verify_url": "https://api.mnemom.ai/v1/verify"
  }
}
```

***

## Design influences

The IntegrityCertificate format draws from two established standards:

* **[C2PA Content Credentials](https://c2pa.org/)**: The concept of a self-describing, machine-readable credential that bundles claims with cryptographic evidence. C2PA uses this pattern for media provenance; AIP adapts it for AI agent integrity.

* **[W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model-2.0/)**: The subject/claims/proofs structure and the `@context` namespace pattern. The certificate acts as a verifiable credential where the issuer is the Mnemom analysis service and the subject is the integrity checkpoint.

Key differences from these standards: AIP certificates use Ed25519 instead of JWS/JWT, include hash chain and Merkle proofs for ordering and completeness guarantees, and support optional zero-knowledge proofs for computational integrity.

***

## See also

* [Verifiable Verdicts](/protocols/aip/verifiable-verdicts) -- Zero-knowledge proofs for verdict derivation
* [AIP Specification -- Attestation](/protocols/aip/specification#16-attestation) -- Protocol-level attestation specification
* [AIP Specification -- Verification](/protocols/aip/specification#17-verification) -- Protocol-level verification specification
* [Security & Trust Model -- Cryptographic Guarantees](/guides/security-trust-model#cryptographic-guarantees) -- How certificates fit into the broader trust model


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.