{
  "openapi": "3.1.0",
  "info": {
    "title": "ChainMemory API",
    "version": "3.0",
    "summary": "Persistent, verifiable memory for AI agents, portable across models.",
    "description": "Memories are the input; **Project State** is the product: a consolidated, versioned view of a project distilled from those memories, with every item traceable to the memories that support it.\n\n**Authentication.** Every endpoint takes an API key in the `x-api-key` header, except those marked as public. Get one at https://faucet.chainmemory.ai\n\n**Fees.** Writing costs AIC, the network's usage credit: 0.001 per memory, 0.001 to assume a role, 0.1 per context injection, 0.05 + 0.005 per op for a state consolidation. Reading and verifying are free.\n\n**Scope of this document.** It covers the endpoints whose request and response contracts have been read in the server source or exercised against production. The API exposes more endpoints than these; the ones still undocumented are listed at the end of this description. They are left out on purpose: a generated client built on guessed schemas compiles and then fails at runtime, which is worse than not describing them at all.\n\nEndpoints that exist but are not yet described here:\n- `/v1/memory/fast`\n- `/v1/memory/attach`\n- `/v1/memory/context`\n- `/v1/memory/context/expanded`\n- `/v1/memory/{id}/forensics`\n- `/v1/memories`\n- `/v1/memories/{id}/trust`\n- `/v1/compress`\n- `/v1/inject/quote`\n- `/v1/audit/memory/{id}`\n- `/v1/audit/state/{project}`\n- `/v1/oracle/query`\n- `/v1/keys`\n- `/v1/keys/register-pubkey`\n- `/v1/seal/{id}`\n- `/v1/metrics`\n- `/v1/billing/status`\n- `/v1/projects/from-default/{id}`\n- `/v1/project/{name}/state/rollback`",
    "contact": {
      "name": "ChainMemory",
      "url": "https://chainmemory.ai"
    },
    "license": {
      "name": "MIT"
    }
  },
  "servers": [
    {
      "url": "https://api.chainmemory.ai",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Full documentation",
    "url": "https://docs.chainmemory.ai"
  },
  "tags": [
    {
      "name": "Memories",
      "description": "Write, search and manage memories"
    },
    {
      "name": "Blind vault",
      "description": "Memories encrypted client-side that the server cannot read"
    },
    {
      "name": "Project Brain",
      "description": "Consolidated, verifiable project state"
    },
    {
      "name": "Role contracts",
      "description": "Signed role contracts and audited sessions"
    },
    {
      "name": "Organizations",
      "description": "Teams: shared budget, member keys and audit trail"
    },
    {
      "name": "Verification",
      "description": "Public proofs: anyone can check an anchor without an API key"
    },
    {
      "name": "Context injection",
      "description": "Load verifiable memories into a model's context"
    },
    {
      "name": "Projects",
      "description": "Project tags"
    },
    {
      "name": "Account",
      "description": "Your identity and counters"
    },
    {
      "name": "Network",
      "description": "Public chain statistics"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Get one free at https://faucet.chainmemory.ai"
      }
    }
  },
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/v1/memory": {
      "post": {
        "tags": [
          "Memories"
        ],
        "summary": "Write a memory",
        "description": "Writes a plaintext memory. The content is encrypted server-side with a key derived from your API key. Fee: 0.001 AIC. Maximum 19936 bytes of UTF-8 text (a single on-chain transaction); larger writes are rejected with 413 and no charge. The `event_hash` is computed when the memory is synced to the chain (~30 s later), not at write time — see the note on evidence in Project Brain.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "summary": {
                    "type": "string",
                    "description": "The memory text"
                  },
                  "category": {
                    "type": "string",
                    "description": "Free-form, e.g. DECISION, INTERACTION, CUSTOM"
                  },
                  "importance": {
                    "type": "integer",
                    "description": "1-10, default 5"
                  },
                  "platform": {
                    "type": "string",
                    "description": "claude, chatgpt, gemini..."
                  },
                  "project": {
                    "type": "string",
                    "description": "Project slug; stored as the first tag"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Up to 10 tags"
                  }
                },
                "required": [
                  "summary"
                ]
              },
              "example": {
                "summary": "Decided to migrate the primary host to Hetzner.",
                "category": "DECISION",
                "importance": 8,
                "project": "chainmemory",
                "tags": [
                  "infra",
                  "migration"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Memory written",
            "content": {
              "application/json": {
                "example": {
                  "memory_number": 617,
                  "event_hash": null,
                  "chain_memory_id": null,
                  "trust": "trusted",
                  "tags": [
                    "chainmemory",
                    "infra"
                  ]
                }
              }
            }
          },
          "402": {
            "description": "insufficient_aic",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_aic",
                  "required_aic": "0.001"
                }
              }
            }
          },
          "413": {
            "description": "memory_too_large — the text would not fit in a single on-chain transaction, so it could never be anchored or cited as evidence. Checked before charging, so nothing is charged (since 2026-09-16)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "memory_too_large",
                  "bytes": 25000,
                  "max_bytes": 19936,
                  "over_by": 5064
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory/sealed": {
      "post": {
        "tags": [
          "Blind vault"
        ],
        "summary": "Store an already-encrypted memory",
        "description": "Blind vault: the client encrypts the content and sends an opaque blob. The server charges the same fee, anchors the hash and stores bytes it cannot read. Unlike a plaintext memory, the `event_hash` comes from the client, so a sealed memory is citable as evidence immediately. Requires a custodial key able to sign the anchor.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "blob_b64": {
                    "type": "string",
                    "description": "Versioned envelope, base64: 0x02 || IV || ciphertext || tag"
                  },
                  "event_hash": {
                    "type": "string",
                    "description": "SHA-256 computed by the client, 32 bytes hex"
                  },
                  "plain_len": {
                    "type": "integer",
                    "description": "Plaintext length, for quota accounting"
                  },
                  "category": {
                    "type": "string"
                  },
                  "importance": {
                    "type": "integer"
                  },
                  "platform": {
                    "type": "string"
                  },
                  "project": {
                    "type": "string"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "blob_b64",
                  "event_hash",
                  "plain_len"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sealed memory stored",
            "content": {
              "application/json": {
                "example": {
                  "memory_id": 640,
                  "memory_number": 616,
                  "scheme": "sealed",
                  "tags": [
                    "chainmemory"
                  ],
                  "chain_sync": "pending"
                }
              }
            }
          },
          "400": {
            "description": "Invalid blob_b64 or event_hash",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "insufficient_aic",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Sealed writes need a custodial key able to sign the anchor",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "413": {
            "description": "Blob too large for one transaction",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory/{id}/blob": {
      "get": {
        "tags": [
          "Blind vault"
        ],
        "summary": "Retrieve a sealed blob for client-side decryption",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "memory_number"
          }
        ],
        "responses": {
          "200": {
            "description": "The encrypted blob",
            "content": {
              "application/json": {
                "example": {
                  "memory_number": 616,
                  "scheme": "sealed",
                  "blob_b64": "AqYz...",
                  "plain_len": 123
                }
              }
            }
          },
          "404": {
            "description": "Memory not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memories/list": {
      "get": {
        "tags": [
          "Memories"
        ],
        "summary": "List memories, newest first",
        "description": "Pages of at most 100. The project filter is applied before paging (since 2026-09-15), so every page holds only memories of that project; follow `next_offset` until it is null. `total` and `total_archived` count the whole account, `total_filtered` counts what matches the filter. Tag matching is exact and case-sensitive.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "1-100, default 50. Larger values are capped at 100"
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Default 0. Use next_offset from the previous page"
          },
          {
            "name": "project",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Exact project tag. `general` returns memories with no tags"
          },
          {
            "name": "archived",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "1 returns ONLY archived memories; omit for active ones"
          },
          {
            "name": "synced",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "1 returns only memories already anchored on-chain"
          },
          {
            "name": "include_plaintext",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "1 adds `summary` with the full text of non-sealed memories. Sealed memories never include it: the server does not have their text"
          }
        ],
        "responses": {
          "200": {
            "description": "A page of memories",
            "content": {
              "application/json": {
                "example": {
                  "memories": [
                    {
                      "id": 757,
                      "memory_number": 727,
                      "summary_preview": "BRAIN v90 CONSOLIDADO Y GUARD POR PROYECTO VERIFICADO EN VIVO...",
                      "summary": "(full text, only with include_plaintext=1)",
                      "summary_length": 1180,
                      "estimated_tokens": 295,
                      "category": "VERIFICACION",
                      "importance": 8,
                      "platform": "claude",
                      "timestamp": 1789435000,
                      "synced_chain": true,
                      "chain_memory_id": 918,
                      "event_hash": "0x…",
                      "tags": [
                        "chainmemory",
                        "brain"
                      ],
                      "archived": false,
                      "inject_count": 0,
                      "trust": "trusted",
                      "scheme": "plain"
                    }
                  ],
                  "count": 50,
                  "total": 733,
                  "total_archived": 49,
                  "total_filtered": 503,
                  "next_offset": 50,
                  "filter": {
                    "project": "chainmemory",
                    "archived": false,
                    "onlySynced": false
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory/{id}/decrypted": {
      "get": {
        "tags": [
          "Memories"
        ],
        "summary": "Read one of your memories from the chain and check it against your record",
        "description": "Takes your `memory_number`. Reads the ciphertext stored on-chain, decrypts it with the key derived from your API key and checks two things: that the text matches the on-chain hash, and (since 2026-09-14) that the on-chain hash matches the `event_hash` of your record (`matches_record`). `integrity_verified` is true only when both hold. A sealed memory is returned as its encrypted blob, never as text: decrypt it on the client.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "memory_number"
          }
        ],
        "responses": {
          "200": {
            "description": "Decrypted memory, or the blob of a sealed one",
            "content": {
              "application/json": {
                "example": {
                  "memory_number": 687,
                  "ai_id": 1,
                  "category": "RISK",
                  "summary": "…",
                  "summary_length": 612,
                  "event_hash": "0x…",
                  "integrity_verified": true,
                  "matches_record": true,
                  "timestamp": 1789339882,
                  "importance": 8,
                  "is_sealed": false
                }
              }
            }
          },
          "403": {
            "description": "caller not registered on chain",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "memory not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "memory not yet anchored on-chain (wait ~30 s after writing)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memories/search": {
      "get": {
        "tags": [
          "Memories"
        ],
        "summary": "Semantic search over your memories",
        "description": "Note: sealed memories are stored with no searchable text and will NOT appear here. They are still found by project or tag with /v1/memories/list.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Natural-language query"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "1-20, default 10"
          }
        ],
        "responses": {
          "200": {
            "description": "Matches with a relevance score",
            "content": {
              "application/json": {
                "example": {
                  "count": 2,
                  "query": "hetzner migration",
                  "memories": [
                    {
                      "id": 617,
                      "summary": "...",
                      "_score": 0.71
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/memories/{id}/archive": {
      "post": {
        "tags": [
          "Memories"
        ],
        "summary": "Archive a memory (reversible)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memories/{id}/unarchive": {
      "post": {
        "tags": [
          "Memories"
        ],
        "summary": "Restore an archived memory",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done"
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memories/{id}/tags": {
      "put": {
        "tags": [
          "Memories"
        ],
        "summary": "Replace the tags of a memory",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "tags"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tags updated"
          }
        }
      }
    },
    "/v1/profile": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Your account and memory counters",
        "description": "Counters for YOUR account only. `local_memories` matches the `total` of /v1/memories/list; `chain_memories` counts what the memory contract holds for your AI id. Network-wide numbers live in /v1/stats and are not comparable with these.",
        "responses": {
          "200": {
            "description": "Profile",
            "content": {
              "application/json": {
                "example": {
                  "ai_id": 1,
                  "owner": "0x46b4...",
                  "chain_memories": 720,
                  "local_memories": 616,
                  "synced_memories": 616,
                  "pending_sync": 0,
                  "reputation": 4831,
                  "active": true
                }
              }
            }
          }
        }
      }
    },
    "/v1/stats": {
      "get": {
        "tags": [
          "Network"
        ],
        "summary": "Public network statistics",
        "security": [],
        "description": "Network-wide, every account. `total_memories` counts write operations on the memory contract, so it runs ahead of `episodic_memories` (rows in the database): before the fix of 2026-09-14 an overlapping sync could write the same memory twice, and those 178 extra writes remain on-chain. For your own account use /v1/profile.",
        "responses": {
          "200": {
            "description": "Network stats",
            "content": {
              "application/json": {
                "example": {
                  "network": "ChainMemory",
                  "chain_id": 202604,
                  "block": 662072,
                  "total_ais": 13,
                  "total_memories": 752,
                  "episodic_memories": 646
                }
              }
            }
          }
        }
      }
    },
    "/v1/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "List your projects",
        "responses": {
          "200": {
            "description": "Projects",
            "content": {
              "application/json": {
                "example": {
                  "count": 7,
                  "projects": [
                    {
                      "id": 1,
                      "project_id": "chainmemory",
                      "name": "chainmemory",
                      "keywords": [
                        "blockchain"
                      ],
                      "color": "#1119e8"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Projects"
        ],
        "summary": "Create a project",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "project_id": {
                    "type": "string",
                    "description": "Short slug"
                  },
                  "name": {
                    "type": "string",
                    "description": "Display name"
                  },
                  "keywords": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Auto-tag keywords. MUST be an array, even if empty"
                  }
                },
                "required": [
                  "project_id",
                  "name"
                ]
              },
              "example": {
                "project_id": "my-project",
                "name": "My Project",
                "keywords": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created"
          },
          "400": {
            "description": "Validation error, e.g. 'keywords must be array'",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/projects/defaults": {
      "get": {
        "tags": [
          "Projects"
        ],
        "summary": "Built-in project templates",
        "responses": {
          "200": {
            "description": "Templates",
            "content": {
              "application/json": {
                "example": {
                  "defaults": [
                    {
                      "project_id": "research",
                      "name": "Research",
                      "keywords": [
                        "paper"
                      ],
                      "description": "..."
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/projects/{id}": {
      "delete": {
        "tags": [
          "Projects"
        ],
        "summary": "Delete a project tag",
        "description": "Takes the NUMERIC id from /v1/projects, not the slug. Passing the slug returns 400 'invalid id'. Memories keep the tag.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Numeric project id"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "400": {
            "description": "invalid id",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/state": {
      "get": {
        "tags": [
          "Project Brain"
        ],
        "summary": "Consolidated, verifiable project state",
        "description": "The distilled state of a project: phase, current focus, decisions with their evidence, risks, priorities, open questions, vocabulary, constraints and the `environment` section (hosts, services, repositories and operating rules). Includes `state_hash` (SHA3-256) for integrity.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_roles",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Embed the full text of every signed role contract"
          }
        ],
        "responses": {
          "200": {
            "description": "Project state, its on-chain anchor and a `provenance` block (since 2026-09-16) counting how many items cite memories and how many carry `evidence_root` 0x000...0 — state with no provenance",
            "content": {
              "application/json": {
                "example": {
                  "project": "chainmemory",
                  "schema_version": 2,
                  "version": 91,
                  "state_hash": "0xf47ce268…",
                  "generated_at": "2026-09-15T21:34:33.000Z",
                  "anchor": {
                    "status": "anchored",
                    "onchain_anchor_id": 98,
                    "tx_hash": "0x…",
                    "block_number": 693319
                  },
                  "provenance": {
                    "items": 208,
                    "with_evidence": 140,
                    "without_evidence": 68,
                    "pct_with_evidence": 67.3,
                    "zero_root": "0x000…0"
                  },
                  "state": {
                    "phase": "…",
                    "decisions": [
                      "…"
                    ]
                  }
                }
              }
            }
          },
          "404": {
            "description": "No state yet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/state/ops": {
      "post": {
        "tags": [
          "Project Brain"
        ],
        "summary": "Apply operations to the project state",
        "description": "Client consolidates, chain verifies. You send operations from the 29-op grammar; the server validates invariants, applies them with a deterministic builder, computes the new `state_hash` and persists it. Fee: 0.05 AIC + 0.005 per applied op.\n\n**Evidence is what makes the state trustworthy.** Cite the memories that support each operation with `evidence_memory_ids`; the server resolves them to event hashes and computes a Merkle `evidence_root`. An operation written without evidence gets `evidence_root 0x000...0` — state with no provenance, indistinguishable from the model's own opinion, and the chain will seal it just the same because it verifies hashes, not correctness.\n\n**If any cited memory cannot be resolved, the whole call is rejected with 422** and nothing is written or charged. The usual cause is citing a plaintext memory before it has been anchored: its `event_hash` is computed on sync (~30 s), not on write. Sealed memories carry their hash from the client and are citable immediately.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ops": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "op": {
                          "type": "string",
                          "description": "Operation type: add_decision, add_milestone, add_risk, set_focus, add_env_host, ..."
                        },
                        "evidence_memory_ids": {
                          "type": "array",
                          "items": {
                            "type": "integer"
                          },
                          "description": "Memory numbers backing this operation"
                        }
                      }
                    },
                    "description": "1-100 operations"
                  },
                  "generated_by": {
                    "type": "string",
                    "description": "Client identifier"
                  },
                  "consolidated_until_event": {
                    "type": "integer",
                    "description": "Highest memory number included in this consolidation"
                  }
                },
                "required": [
                  "ops"
                ]
              },
              "example": {
                "ops": [
                  {
                    "op": "add_milestone",
                    "status": "done",
                    "title": "Primary host migrated to Hetzner.",
                    "evidence_memory_ids": [
                      617,
                      618
                    ]
                  }
                ],
                "consolidated_until_event": 618
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "State updated",
            "content": {
              "application/json": {
                "example": {
                  "version": 85,
                  "state_hash": "0x09a8...",
                  "applied_count": 2,
                  "rejected": [],
                  "ops_log": [],
                  "provenance_warning": {
                    "ops_sin_evidencia": [
                      {
                        "index": 0,
                        "op": "add_milestone"
                      }
                    ],
                    "memorias_sin_consolidar": 12
                  }
                }
              }
            }
          },
          "200": {
            "description": "No change: every op was rejected, or the resulting hash is identical"
          },
          "422": {
            "description": "evidence_unresolved — cited memories could not be resolved; nothing written, nothing charged",
            "content": {
              "application/json": {
                "example": {
                  "error": "evidence_unresolved",
                  "sin_anclar": 12,
                  "no_existen": 0,
                  "ops": [
                    {
                      "index": 0,
                      "op": "add_milestone",
                      "citadas": 13,
                      "resueltas": 1,
                      "sin_anclar": [
                        618,
                        619
                      ]
                    }
                  ]
                }
              }
            }
          },
          "402": {
            "description": "insufficient_aic",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/state/anchor": {
      "get": {
        "tags": [
          "Project Brain"
        ],
        "summary": "On-chain anchor of a state version",
        "security": [],
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Defaults to the latest anchored"
          }
        ],
        "responses": {
          "200": {
            "description": "Anchor"
          },
          "404": {
            "description": "No anchors yet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/roles": {
      "get": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Roles defined for a project",
        "description": "Role ids are not guessable: list them before assuming one. Only contracts with status `active` can be assumed.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Roles",
            "content": {
              "application/json": {
                "example": {
                  "project": "chainmemory",
                  "roles": [
                    {
                      "role_id": "charly",
                      "version": 2,
                      "status": "active",
                      "contract_hash": "0x1a55...",
                      "author": "silvio",
                      "signed_at": 1784810494
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/role/{roleId}": {
      "get": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Read a Verifiable Role Contract in full",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "roleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Audit a past version"
          }
        ],
        "responses": {
          "200": {
            "description": "Contract: purpose, rules with severity, working protocol"
          },
          "404": {
            "description": "role contract not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/role/{roleId}/assume": {
      "post": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Open an audited session under a role",
        "description": "Pins the contract version and hash plus the Brain state hash at that instant, and returns the owner's declared working environment. Fee: 0.001 AIC. Auto-releases after 60 minutes. One open session per role.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "roleId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "platform": {
                    "type": "string",
                    "description": "Executor: claude, chatgpt, gemini"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session open",
            "content": {
              "application/json": {
                "example": {
                  "session_id": 24,
                  "contract_version": 2,
                  "contract_hash": "0x1a55...",
                  "brain_version": 85,
                  "auto_release_minutes": 60
                }
              }
            }
          },
          "404": {
            "description": "role contract not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "contract not active, or the role already has an open session",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "insufficient_aic",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/session/{id}/release": {
      "post": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Close a role session with a summary",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "summary": {
                    "type": "string",
                    "description": "What was done, what is pending, what comes next. Max 4000 chars"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Released",
            "content": {
              "application/json": {
                "example": {
                  "session_id": 24,
                  "release_type": "manual",
                  "duration_seconds": 34
                }
              }
            }
          },
          "404": {
            "description": "session not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "session already released",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/session/{id}": {
      "get": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Read one session and everything it was pinned to",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session"
          },
          "404": {
            "description": "session not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/project/{name}/sessions": {
      "get": {
        "tags": [
          "Role contracts"
        ],
        "summary": "Audit trail of a project's role sessions",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Sessions: who assumed which role, on what platform, how it closed"
          }
        }
      }
    },
    "/v1/org": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Create an organization",
        "description": "Authenticated with your personal key. One key can own one organization. It starts `suspended`: reads work, issuing keys and inviting return 402 until it is activated.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "org_slug": {
                    "type": "string",
                    "description": "3-40 chars: lowercase, digits and hyphens; cannot start or end with a hyphen"
                  },
                  "name": {
                    "type": "string"
                  },
                  "owner_email": {
                    "type": "string",
                    "description": "Becomes the first member, role owner"
                  },
                  "tier": {
                    "type": "string",
                    "description": "team or enterprise"
                  }
                },
                "required": [
                  "org_slug",
                  "name",
                  "owner_email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created",
            "content": {
              "application/json": {
                "example": {
                  "org_id": 3,
                  "org_slug": "acme-labs",
                  "tier": "team"
                }
              }
            }
          },
          "400": {
            "description": "Invalid slug or missing field",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "This key already owns an organization",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "Read status and plan",
        "responses": {
          "200": {
            "description": "Organization"
          },
          "401": {
            "description": "no_org_context",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/org/invite": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Add a member",
        "description": "Requires the `members` permission.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string",
                    "description": "owner, admin, developer or viewer"
                  }
                },
                "required": [
                  "email"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member added"
          },
          "400": {
            "description": "valid email required",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "organization_not_active",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "forbidden — your role lacks the permission",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Already a member",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/org/members": {
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List members",
        "responses": {
          "200": {
            "description": "Members"
          }
        }
      }
    },
    "/v1/org/members/{id}/role": {
      "patch": {
        "tags": [
          "Organizations"
        ],
        "summary": "Change a member's role",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "description": "owner, admin, developer or viewer"
                  }
                },
                "required": [
                  "role"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role changed"
          },
          "400": {
            "description": "invalid role",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "member not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "cannot demote the last owner",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/org/members/{id}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Remove a member and revoke their keys",
        "description": "What the member already wrote stays in the organization, attributed to them. Access ends; history does not.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Removed",
            "content": {
              "application/json": {
                "example": {
                  "member_id": 4,
                  "status": "removed",
                  "keys_revoked": 1
                }
              }
            }
          },
          "404": {
            "description": "member not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "cannot remove an owner — change their role first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/org/keys": {
      "post": {
        "tags": [
          "Organizations"
        ],
        "summary": "Issue a member or project key",
        "description": "The full key is returned ONCE in this response and never again; afterwards only its 12-character prefix is shown. A member holds one active key at a time.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "description": "member or project"
                  },
                  "member_id": {
                    "type": "integer",
                    "description": "Required for type=member"
                  },
                  "project_slug": {
                    "type": "string",
                    "description": "Required for type=project"
                  },
                  "role_cap": {
                    "type": "string",
                    "description": "Ceiling on what the key can do"
                  },
                  "expires_days": {
                    "type": "integer",
                    "description": "Expiry, for project keys"
                  }
                },
                "required": [
                  "type"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Key issued",
            "content": {
              "application/json": {
                "example": {
                  "api_key": "aicm_...",
                  "type": "member",
                  "key_prefix": "aicm_d4e133d"
                }
              }
            }
          },
          "402": {
            "description": "project key limit reached for your plan",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Member already has an active key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Organizations"
        ],
        "summary": "List active keys (prefix only)",
        "responses": {
          "200": {
            "description": "Keys"
          }
        }
      }
    },
    "/v1/org/keys/{id}": {
      "delete": {
        "tags": [
          "Organizations"
        ],
        "summary": "Revoke a key",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked"
          },
          "404": {
            "description": "key not found or not active",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/memory/{id}/verify": {
      "get": {
        "tags": [
          "Verification"
        ],
        "summary": "Read a memory's on-chain record",
        "security": [],
        "description": "Public, no API key. Reads the record straight from the memory contract. The `id` is the GLOBAL on-chain id (`chain_memory_id`), not your `memory_number`: get it from /v1/my/memory/{seq}/proof. Returns the event hash and metadata. The ciphertext is not returned by this endpoint (since 2026-09-14); it remains stored on-chain and anyone can read it with `getMemory()` through the public RPC, but it cannot be decrypted without the owner's key.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "chain_memory_id"
          }
        ],
        "responses": {
          "200": {
            "description": "On-chain record",
            "content": {
              "application/json": {
                "example": {
                  "memory_id": 664,
                  "ai_id": 1,
                  "category": "DECISION",
                  "summary_length": 3632,
                  "event_hash": "0x2b6f51ac…",
                  "encrypted_summary_size": 3660,
                  "timestamp": 1757780000,
                  "importance": 8,
                  "is_sealed": false,
                  "contract": "0x…",
                  "chain_id": 202604
                }
              }
            }
          },
          "400": {
            "description": "invalid memory id",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "memory not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/my/memory/{seq}/proof": {
      "get": {
        "tags": [
          "Verification"
        ],
        "summary": "Get a shareable anchoring proof for one of your memories",
        "description": "Starts from your `memory_number` and returns the coordinates a third party needs to check the anchor on-chain without your API key. While the memory is not yet synced (~30 s after writing), `anchored` is false and the hash fields are null.",
        "parameters": [
          {
            "name": "seq",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "memory_number"
          }
        ],
        "responses": {
          "200": {
            "description": "Proof",
            "content": {
              "application/json": {
                "example": {
                  "memory_number": 489,
                  "event_hash": "0x…",
                  "anchored": true,
                  "chain_memory_id": 664,
                  "chain_tx": "0x…",
                  "batch_root": null,
                  "chain_id": 202604,
                  "contract": "0x…"
                }
              }
            }
          },
          "404": {
            "description": "memory not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify-memory": {
      "post": {
        "tags": [
          "Verification"
        ],
        "summary": "Verify a memory's Merkle inclusion",
        "security": [],
        "description": "Public, no API key. POST only: a GET returns 404. Mode `stored` looks the proof up by itself from `memory_id` or `event_hash` and reports whether the batch was anchored. Modes `light` and `full` (default when `mode` is omitted) verify a proof the client supplies and require `event_hash`, `proof` and `batch_root`. Only hashes and metadata are returned, never content.\n\nIMPORTANT: a Merkle proof exists only for memories that went through a compression batch (POST /v1/compress). Every other memory returns `valid: false` with `anchor_status: \"uncompressed\"` — that does NOT mean it is unanchored. Each memory is written to the memory contract individually when it syncs; check that with /v1/my/memory/{seq}/proof and /v1/memory/{id}/verify.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mode": {
                    "type": "string",
                    "enum": [
                      "stored",
                      "light",
                      "full"
                    ],
                    "description": "Default: full"
                  },
                  "memory_id": {
                    "type": "integer",
                    "description": "mode=stored: internal memory id"
                  },
                  "event_hash": {
                    "type": "string",
                    "description": "mode=stored alternative to memory_id; required for light/full"
                  },
                  "proof": {
                    "description": "light/full: Merkle proof"
                  },
                  "batch_root": {
                    "type": "string",
                    "description": "light/full"
                  },
                  "memory": {
                    "description": "full: the memory object"
                  },
                  "content_hash": {
                    "type": "string",
                    "description": "full"
                  },
                  "daily_root": {
                    "type": "string",
                    "description": "full"
                  }
                }
              },
              "example": {
                "mode": "stored",
                "event_hash": "0x2b6f51ac…"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result. For mode=stored the shape is shown; light/full return the verifier's own result object.",
            "content": {
              "application/json": {
                "example": {
                  "valid": true,
                  "found": true,
                  "mode": "stored",
                  "memory_id": 612,
                  "event_hash": "0x…",
                  "batch_root": "0x…",
                  "batch_id": 41,
                  "leaf_index": 3,
                  "anchor_status": "anchored",
                  "checkpoint_id": 12,
                  "checkpoint_tx_hash": "0x…",
                  "block_number": 80467,
                  "verified_at": 1757780000,
                  "merkle_version": "v2"
                }
              }
            }
          },
          "400": {
            "description": "Missing fields for the chosen mode",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "event_hash, proof and batch_root required for mode=light/full"
                }
              }
            }
          },
          "404": {
            "description": "mode=stored: memory not found",
            "content": {
              "application/json": {
                "example": {
                  "valid": false,
                  "found": false,
                  "reason": "Memory not found"
                }
              }
            }
          }
        }
      }
    },
    "/v1/verify/{name}": {
      "get": {
        "tags": [
          "Verification"
        ],
        "summary": "List a project's on-chain state anchors",
        "security": [],
        "description": "Public, no API key. Returns every anchored version of a Project Brain with its `state_hash` and on-chain coordinates in the ProjectStateAnchor contract, never the state itself. To verify: `getAnchorById(anchor_id)` returns (projectId, version, stateHash, anchoredAt, anchoredBy); `stateHash` must equal `state_hash` for that version.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Project slug"
          }
        ],
        "responses": {
          "200": {
            "description": "Anchors",
            "content": {
              "application/json": {
                "example": {
                  "project": "chainmemory",
                  "chain": {
                    "chainId": 202604,
                    "rpc": "https://rpc.chainmemory.ai",
                    "contract": "0xa7A8BA51950255b3e223a6745597C67009Fe7875",
                    "contract_name": "ProjectStateAnchor"
                  },
                  "latest_version": 86,
                  "latest_state_hash": "0x…",
                  "anchors": [
                    {
                      "version": 86,
                      "state_hash": "0x…",
                      "anchor_id": 90,
                      "tx_hash": "0x…",
                      "block_number": 678000,
                      "anchored_at": "2026-09-12T16:00:00.000Z",
                      "status": "anchored"
                    }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/inject": {
      "post": {
        "tags": [
          "Context injection"
        ],
        "summary": "Inject memories into a conversation",
        "description": "Returns the selected memories plus `inject_text`, a ready-to-paste block that tells the model to cite each memory by its #N. Fee: 0.1 AIC (half burned, half to treasury). Quarantined and archived memories are skipped silently. With `optimistic: true` the response comes back immediately and the payment settles in the background: poll /v1/inject/status/{id} with `payment.inject_log_id`. Sealed memories come back as ciphertext (`content_blob`, `scheme` 2) and as a placeholder inside `inject_text`; the client decrypts them.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "memory_ids": {
                    "type": "array",
                    "items": {
                      "type": "integer"
                    },
                    "description": "memory_numbers, 1-50"
                  },
                  "optimistic": {
                    "type": "boolean",
                    "description": "Respond before the payment confirms"
                  },
                  "project_filter": {
                    "type": "string",
                    "description": "Recorded in the history only"
                  },
                  "target_platform": {
                    "type": "string",
                    "description": "Recorded in the history only"
                  }
                },
                "required": [
                  "memory_ids"
                ]
              },
              "example": {
                "memory_ids": [
                  612,
                  613
                ],
                "optimistic": true,
                "target_platform": "claude"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Injected",
            "content": {
              "application/json": {
                "example": {
                  "injected": 2,
                  "memories": [
                    {
                      "id": 740,
                      "user_seq": 612,
                      "summary": "…",
                      "category": "DECISION",
                      "importance": 8,
                      "timestamp": 1757780000,
                      "tags": [
                        "chainmemory"
                      ],
                      "event_hash": "0x…",
                      "chain_memory_id": 664,
                      "content_blob": null,
                      "scheme": null,
                      "plain_len": null
                    }
                  ],
                  "inject_text": "[Estas memorias son verificables on-chain…]\n\n[Memoria #612 · ref:740 · chain:664 · DECISION · verificable on-chain]\n…",
                  "payment": {
                    "charged_aic": "0.1",
                    "status": "pending",
                    "inject_log_id": 51
                  },
                  "stats": {
                    "memory_count": 2,
                    "total_chars": 1840,
                    "estimated_tokens": 460
                  }
                }
              }
            }
          },
          "400": {
            "description": "memory_ids missing or more than 50",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "insufficient_aic",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "error": "insufficient_aic",
                  "required_aic": "0.1",
                  "faucet_url": "https://faucet.chainmemory.ai"
                }
              }
            }
          },
          "404": {
            "description": "none of the ids is a valid memory of this key",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "payment_failed (non-optimistic mode only)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/inject/balance": {
      "get": {
        "tags": [
          "Context injection"
        ],
        "summary": "Balance and injections left",
        "responses": {
          "200": {
            "description": "Balance",
            "content": {
              "application/json": {
                "example": {
                  "wallet": "0x…",
                  "balance_wei": "4200000000000000000",
                  "balance_aic": "4.2",
                  "cost_per_inject_aic": "0.1",
                  "injects_remaining": "42",
                  "faucet_url": "https://faucet.chainmemory.ai"
                }
              }
            }
          }
        }
      }
    },
    "/v1/inject/status/{id}": {
      "get": {
        "tags": [
          "Context injection"
        ],
        "summary": "Payment status of an optimistic injection",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "payment.inject_log_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "example": {
                  "id": 51,
                  "status": "confirmed",
                  "tx_hash": "0x…,0x…",
                  "timestamp": 1757780000
                }
              }
            }
          },
          "404": {
            "description": "not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/inject/history": {
      "get": {
        "tags": [
          "Context injection"
        ],
        "summary": "Your injection history",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Max 100, default 20"
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "Default 0"
          }
        ],
        "responses": {
          "200": {
            "description": "History. `memory_ids` holds internal ids, not memory_numbers; totals count confirmed injections only.",
            "content": {
              "application/json": {
                "example": {
                  "history": [
                    {
                      "id": 51,
                      "memory_ids": [
                        740,
                        741
                      ],
                      "project_filter": null,
                      "memory_count": 2,
                      "token_count": 460,
                      "aic_charged": "0.1",
                      "aic_burned": "0.05",
                      "aic_treasury": "0.05",
                      "tx_hash": "0x…,0x…",
                      "target_platform": "claude",
                      "timestamp": 1757780000,
                      "success": true,
                      "status": "confirmed"
                    }
                  ],
                  "totals": {
                    "total_injects": 1,
                    "total_memories_injected": 2,
                    "total_tokens": 460,
                    "total_aic_spent": "0.100000",
                    "total_aic_burned": "0.050000"
                  },
                  "count": 1
                }
              }
            }
          }
        }
      }
    },
    "/v1/register": {
      "post": {
        "tags": [
          "Account"
        ],
        "summary": "Register your AI identity on-chain",
        "description": "Optional: the first memory sync registers you automatically as `auto-<address>`. Call this first if you want a real name and model on-chain. Once registered, calling it again returns `already_registered` and changes nothing.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "model": {
                    "type": "string"
                  }
                },
                "required": [
                  "name",
                  "model"
                ]
              },
              "example": {
                "name": "research-agent",
                "model": "claude-opus-5"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registered, or already registered",
            "content": {
              "application/json": {
                "example": {
                  "ai_id": 14,
                  "name": "research-agent",
                  "model": "claude-opus-5",
                  "tx": "0x…"
                }
              }
            }
          },
          "400": {
            "description": "name and model required",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
