REST API

Machine-readable contract: OpenAPI 3.1. Orientation for LLMs: api.chainmemory.ai/llms.txt.

Authentication

All API calls require authentication via API Key in the header:

HTTP
x-api-key: your-api-key

Base URL: https://api.chainmemory.ai/v1

Security Never expose your API Key in frontend code or public repositories. Use it only in backend or in environment variables.

Memories

POST /v1/memory

Create a new memory. Fee: 0.001 AIC

bash
curl -X POST https://api.chainmemory.ai/v1/memory \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "summary": "Decided to use PostgreSQL instead of MongoDB",
    "category": "decision",
    "importance": 8,
    "platform": "manual"
  }'
javascript
const res = await fetch('https://api.chainmemory.ai/v1/memory', {
  method: 'POST',
  headers: {
    'x-api-key': 'your-api-key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    summary: 'Decided to use PostgreSQL instead of MongoDB',
    category: 'decision',
    importance: 8,
    platform: 'api'
  })
});
const memory = await res.json();
// { id: 207, hash: '0x4f2a...', memory_number: 42 }
python
import requests

res = requests.post(
    'https://api.chainmemory.ai/v1/memory',
    headers={'x-api-key': 'your-api-key'},
    json={
        'summary': 'Decided to use PostgreSQL instead of MongoDB',
        'category': 'decision',
        'importance': 8,
        'platform': 'api'
    }
)
memory = res.json()
# {'id': 207, 'hash': '0x4f2a...', 'memory_number': 42}

Parameters

ParameterTypeDescription
summary*stringText of the memory. The only required field
projectstringProject to link it to. Optional: without it, tags are inferred from your projects keywords
tagsstring[]Tags for organization (max 10)
platformstringOrigin label: manual, extension, mcp, api. Defaults to api
categorystringDECISION, LEARNING, INTERACTION, STATE, ERROR, MILESTONE or CUSTOM. Defaults to CUSTOM
importancenumber1 to 10, clamped to that range. Defaults to 5
GET /v1/memories/list

List memories with optional filters.

ParameterTypeDescription
projectstringFilter by project
tagsstringFilter by tags (comma-separated)
searchstringSearch in content
limitnumberMaximum results (default: 20)
offsetnumberPagination offset
GET /v1/memories/search

Semantic search by content, tags, project, or date range.

Projects

GET /v1/projects

List all user projects.

GET /v1/project/:name/state

Get the consolidated project state (decisions, milestones, risks, priorities, open questions, environment).

Response (trimmed)
{
  "project": "payment-system",
  "schema_version": 2,
  "version": 4,
  "state_hash": "0x3f8c2a…e91d",
  "generated_at": "2026-09-13T22:02:35.000Z",
  "anchor": { "status": "anchored", "onchain_anchor_id": 12, "tx_hash": "0x…", "block_number": 681919 },
  "state": {
    "phase": "beta",
    "current_focus": "PCI review before opening to the first tenants",
    "decisions": [
      { "id": "dec_0002", "title": "PostgreSQL with RLS for multi-tenancy",
        "statement": "Row-level security removes tenant filtering from the application layer",
        "status": "confirmed", "superseded_by": null,
        "evidence_root": "0x9a41…c07e", "created_version": 2, "updated_version": 3 }
    ],
    "milestones": [
      { "id": "mil_0001", "title": "Database schema", "status": "done",
        "evidence_root": "0x5b2d…81fa", "created_version": 1, "updated_version": 2 }
    ],
    "risks": [
      { "id": "risk_0001", "title": "RLS performance at 100K tenants", "severity": "med", "status": "open",
        "evidence_root": "0xd7e0…2a19", "created_version": 3, "updated_version": 3 }
    ],
    "state_meta": { "version": 4, "consolidated_until_event": 150, "previous_state_hash": "0x7b2e…f4c0" }
  }
}

Always the latest version; requires the owner's API key. Severity values are low, med and high.

GET /v1/project/:name/inject

The project's Brain as text ready to paste into a chat, ordered by relevance and cut to a character budget. Free.

ParameterTypeDescription
budgetnumberMaximum characters, 1,000 to 50,000 (default 7,000). The most relevant sections are kept whole; the rest is shortened to fit
langstringen (default) or es: the language of the headings. Items are returned as they were written
sincenumberVersion to compare against for the "what changed" section. Default: the previous version
taskstringA priority id such as pri_0015. Returns everything needed to work on that priority instead of the overview: the priority in full with its completion criterion, the risks it mitigates, what else mentions it, and every work rule and constraint
levelstringpublic (default) or full. See below
Response (trimmed)
{
  "project": "payment-system",
  "version": 4,
  "state_hash": "0x3f8c2a…e91d",
  "level": "public",
  "budget": 7000,
  "lang": "en",
  "since": 3,
  "length": 2841,
  "text": "[ChainMemory · Project State: payment-system v4]
…"
}

With task, the response carries task instead of since. Always the latest version; requires the owner's key or an organization key with access to the project (a project key only reads its own project).

Public by default, full only with the owner's approval At the public level, addresses, ports, server paths and security rules are replaced by [withheld] and counted, so the text is safe to paste into any chat. How a project's AIC are safeguarded is never included, at any level. The full level adds the withheld details; it is served only to the owner's personal key (an organization key gets 403), and every request is logged with a fingerprint of the key, the project, the version, the task, the client and the number of sensitive lines. Its response adds sensitive_lines: exactly the lines the public level would have withheld, so the client can show them to the owner before anything is pasted. If the log cannot be written, the full level is not served (503). Send an x-cm-client header to name your client in that log.
GET /v1/project/:name/inject/log

The last 100 full-level requests for this project: version, task, client, number of sensitive lines and date. Owner's key only.

Injection

POST /v1/inject

Get relevant memories formatted for prompt injection. Fee: 0.1 AIC

ParameterTypeDescription
memory_ids*number[]Your memory numbers (#N), 1 to 50. Archived and quarantined memories are excluded automatically
project_filterstringOptional project label recorded with the injection
target_platformstringOptional destination label (chatgpt, claude, gemini...)
optimisticbooleanReturn the text immediately and confirm the on-chain payment in the background

Response

The endpoint returns the selected memories formatted for injection. Each memory arrives tagged with its user-facing number and a verification reference, so an AI can cite the exact memory behind any statement — and you can trace that citation back to its on-chain evidence. A claim stops being "trust me" and becomes "here's the memory, verify it yourself."

POST /v1/seal/:id

Seal a memory, making it permanently immutable on-chain. Fee: 0.001 AIC

ParameterTypeDescription
id*numberMemory ID to seal (URL parameter)
POST /v1/project/:name/state

Write a new project state version. Only charged if state actually changed. Fee: 0.1 AIC

ParameterTypeDescription
state*objectThe full project state object
expected_versionnumberOptimistic concurrency check
POST /v1/project/:name/state/ops

Apply operations to project state (Brain consolidation). Fee scales with number of operations applied. Fee: 0.05 + 0.005/op AIC

ParameterTypeDescription
ops*arrayArray of operations to apply (max 100)
consolidated_until_eventnumberEvent cursor for consolidation tracking
generated_bystringClient identifier
Evidence is checked before anything is written Each op cites its supporting memories in evidence_memory_ids. If any cited memory does not exist, is not yours or is not anchored yet, the whole call returns 422 evidence_unresolved with the list of what failed, and nothing is written or charged. Ops that cite nothing are accepted with evidence_root 0x000…0, and the response carries a provenance_warning.

Audit & Oracle

POST /v1/audit/memory/:id

Audit the integrity of a specific memory: verifies hash consistency and on-chain status. Fee: 0.1 AIC

ParameterTypeDescription
id*numberMemory ID to audit (URL parameter)

Response

Returns chain verification (on-chain status, sealed status, tx hash) and hash verification (stored vs computed event hash match). Never exposes memory content to external parties.

POST /v1/audit/state/:project

Full audit of a project: state hash verification, on-chain anchor check, version history, and memory count. Fee: 5 AIC

ParameterTypeDescription
project*stringProject name to audit (URL parameter)

Response

Returns hash verification (stored vs recomputed), anchor status (on-chain ID, tx, block), version history (last 20 versions), and total memory count. The most comprehensive verification available.

POST /v1/oracle/query

Blind Oracle query: derives insights from memory metadata without accessing content. Returns verification proof. Fee: 0.1 AIC

ParameterTypeDescription
question*stringThe question to query
projectstringFilter by project
memory_idsarraySpecific memory IDs to consult

Response

Returns categories involved, time range, memory count attestation, and a SHA-256 query hash for verification. The oracle never accesses or returns memory content — only cryptographic proofs and derived metadata.

Verification

GET /v1/project/:name/state/anchor

Verify the on-chain anchor of a project state. Public endpoint, no authentication required.

ParameterTypeDescription
versionnumberSpecific version (default: latest)
Response
{
  "project": "chainmemory",
  "projectId": "0x77f7d980...",
  "version": 3,
  "state_hash": "a7b3c9f2...",
  "anchor": {
    "status": "anchored",
    "tx_hash": "0xce55a800a2a4e30b...",
    "block_number": 123539,
    "contract": "0xa7A8BA51950255b3e223a6745597C67009Fe7875"
  }
}
Independent verification Anyone can verify the state by calling this endpoint and comparing the state_hash with the one recorded in the on-chain contract. No account or API key needed.

Error Codes

CodeMeaningSolution
401Invalid or missing API KeyCheck your x-api-key header
402insufficient_aic — not enough AIC for a paid operationResponse includes balance_aic, required_aic and faucet_url. Top up at the faucet
403No permissions for this resourceVerify that the project belongs to you
404Resource not foundCheck the project name or ID
409version conflict (POST /v1/project/:name/state with expected_version)Re-read the state and retry
422evidence_unresolved — a cited memory does not exist, is not yours or is not anchored yetWait ~30 s for anchoring, or fix the memory numbers. Nothing was written or charged
429Too many requests from your IPWait and retry. The only limit enforced today is 30 requests per second per IP at the proxy; the per-plan requests-per-minute figures are not enforced yet (see Limits)
429key_creation_limit — POST /v1/keysAt most 3 new keys per IP and 100 in total every 24 hours. The response includes retry_after_seconds
500Internal errorRetry. If persistent, contact support

Feature Equivalence: Extension ↔ MCP ↔ API

Not every feature is available through every integration method. This table shows what's available where:

FeatureExtensionMCPAPI REST
Save memory✓ 1-click save✓ chainmemory_remember✓ POST /v1/memory
Recall memories✓ Memory list✓ chainmemory_recall✓ GET /v1/memories/list
Search memories~ Basic filter✓ search_memories✓ GET /v1/memories/search
Inject context✓ Auto-inject✓ inject_memories✓ POST /v1/inject
Project Brain brief (overview or one task)✓ Inject project state✓ get_project_brief✓ GET /v1/project/:name/inject
Full Project State (JSON)✗ Not available✓ get_project_state✓ GET /v1/project/:name/state
Seal (anchor on-chain)✗ Not available✓ chainmemory_seal✓ POST /v1/seal/:id
Account stats✓ Dashboard✓ chainmemory_stats✓ GET /v1/stats
Profile info✓ Settings✓ chainmemory_profile✓ GET /v1/profile
List projects✓ Project selector✓ list_projects✓ GET /v1/projects
Create project✓ New Project✓ create_project✓ POST /v1/projects
Verify anchor~ Via Explorer link✓ verify_project_state, get_memory_proof✓ GET /v1/project/:name/state/anchor
Archive memory✓✓ archive_memory✓ POST /v1/memories/:id/archive
Update tags✓✓ update_memory_tags✓ PUT /v1/memories/:id/tags
Full API parity Every feature in this table is reachable through the REST API. The remaining gaps are on the Extension side: it does not seal memories, and its search is a local filter over the memory list rather than the semantic search. Both are available through the MCP server and the API.

Trust & Governance

Every memory carries a trust status from the moment it is written: trusted, tentative (flagged at write time by deterministic screening rules), or quarantined (condemned by the owner). Tentative memories are always delivered marked — agents see the flag and decide. Quarantined memories are excluded from context, injection, quotes and oracle queries, while their on-chain fingerprint remains as immutable evidence. All read responses include a trust field.

POST /v1/memories/:id/trust

Govern the trust status of a memory. Owner only.

bash
curl -X POST https://api.chainmemory.ai/v1/memories/487/trust \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"action": "quarantine"}'

Actions: approve → trusted · quarantine → quarantined · tentative → tentative. Response includes the previous status for auditability.

GET /v1/memory/:id/forensics

Complete biography of a memory as an ordered timeline. Owner only.

bash
curl https://api.chainmemory.ai/v1/memory/485/forensics \
  -H "x-api-key: your-api-key"

Timeline events: born, trust, batched, checkpoint_anchored, recalled (every read, with endpoint and query), injected (every delivery, with target platform), cited_as_evidence (Project Brain items citing this memory). Includes cross-checked counters and on-chain anchoring proof. This answers the forensic question: which memory caused what, when did it enter, who read it, and where did it go.

POST /v1/project/:name/state/rollback

Restore project state to a prior version, verifiably. Fee: 0.1 AIC

bash
curl -X POST https://api.chainmemory.ai/v1/project/myproject/state/rollback \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{"to_version": 35}'

Append-only restore: rolling back to version N never deletes anything — it creates a new version whose content is byte-identical to N. Since hashes are computed over canonical bytes, the new version's hash equals the hash already anchored on-chain for N: the faithfulness of the restoration is a mathematical fact, not a promise. Before restoring, the server re-computes the stored content's hash and refuses (HTTP 409) if it does not match — corruption can never be restored. History is never mutated.