{"openapi":"3.1.0","info":{"title":"Reflect Memory Agent API","version":"3.0.0","description":"Cross-agent memory system. Write, read, update, delete, search, browse, and query structured memories. Use updateMemory to edit an existing memory (preserves version history). Use deleteMemory to soft-delete (moves to trash, recoverable from dashboard). Use searchMemories for full-text search with full content returned. Use readMemories for bulk recent memories with full content. Use browseMemories to discover what exists (summaries only, no content). Use getMemoryById for surgical full-body retrieval by UUID. Use getMemoriesByTag for full-body retrieval by topic. Use getLatestMemory for the single most recent memory (strict chronological). Use readTeamMemories and shareMemory for team knowledge sharing. Use /query with specific filters to get AI responses grounded in relevant context. IMPORTANT: For \"most recent memory chronologically\" always use getLatestMemory, not /query. IMPORTANT: To edit a memory, use updateMemory with the memory ID, not writeMemory. IMPORTANT: Never add optional filter parameters (tag, origin, etc.) unless the user explicitly requests filtering. Adding parameters silently narrows results and causes the user to miss their actual data.\n"},"servers":[{"url":"https://api.reflectmemory.com"}],"components":{"schemas":{},"securitySchemes":{"oauth":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://api.reflectmemory.com/chatgpt/authorize","tokenUrl":"https://api.reflectmemory.com/chatgpt/token","scopes":{"memory:read":"Read memories","memory:write":"Write, update, and delete memories"}}}}}},"security":[{"oauth":["memory:read","memory:write"]}],"paths":{"/agent/memories":{"post":{"operationId":"writeMemory","x-openai-isConsequential":false,"summary":"Write a structured memory entry","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","tags","allowed_vendors"],"properties":{"title":{"type":"string","description":"Short descriptor. Format: 'Architecture Update - <topic>'"},"content":{"type":"string","description":"Structured summary. Use format: Change / Reason / Impact / Open Questions"},"tags":{"type":"array","items":{"type":"string"},"description":"Always include 'project_state' and 'architecture'"},"allowed_vendors":{"type":"array","items":{"type":"string"},"description":"Which vendors can see this. Use ['*'] for all."},"memory_type":{"type":"string","enum":["semantic","episodic","procedural"],"default":"semantic","description":"Memory classification. semantic = facts/knowledge, episodic = events/decisions, procedural = workflows/patterns"}}}}}},"responses":{"201":{"description":"Memory created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string","description":"Memory type: semantic, episodic, or procedural"}}}}}}}}},"/agent/memories/latest":{"get":{"operationId":"getLatestMemory","x-openai-isConsequential":false,"summary":"Get the single most recent memory (strict chronological)","description":"Returns the single most recent memory by created_at. IMPORTANT: Call with NO parameters by default. Do NOT add tag or origin unless the user explicitly asks. Adding params silently filters results and hides the actual latest memory. When in doubt, omit all params.\n","parameters":[{"name":"tag","in":"query","required":false,"schema":{"type":"string"},"description":"ONLY use when the user explicitly asks to filter by a specific tag. Do NOT add this parameter on your own. Omit entirely for the true latest memory."},{"name":"origin","in":"query","required":false,"schema":{"type":"string"},"description":"ONLY use when the user explicitly says 'from Cursor' or 'from ChatGPT' etc. Do NOT add this parameter on your own. Omit entirely for the true latest memory."}],"responses":{"200":{"description":"The most recent memory","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string","description":"Memory type: semantic, episodic, or procedural"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}},"404":{"description":"No memories found"}}}},"/agent/memories/{id}":{"get":{"operationId":"getMemoryById","x-openai-isConsequential":false,"summary":"Get a single memory by ID (full body)","description":"Deterministic full-body retrieval of a specific memory by its UUID. Use this for surgical access: council reviews, audit, governance, or when you already know the memory ID from browse results. Returns 404 if the memory doesn't exist or you don't have access.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The memory UUID"}],"responses":{"200":{"description":"The full memory entry","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string","description":"Memory type: semantic, episodic, or procedural"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}},"404":{"description":"Memory not found or not accessible"}}},"put":{"operationId":"updateMemory","x-openai-isConsequential":true,"summary":"Update an existing memory by ID (full replacement)","description":"Edit a memory you own. Replaces title, content, tags, and allowed_vendors. Preserves version history. Use to correct or refine instead of duplicating. Only your own non-trashed memories can be updated.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The memory UUID to update"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","tags","allowed_vendors"],"properties":{"title":{"type":"string","maxLength":500,"description":"Updated title"},"content":{"type":"string","maxLength":100000,"description":"Updated content (full replacement, not a patch)"},"tags":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Updated tags"},"allowed_vendors":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"Which vendors can see this. Use ['*'] for all."}}}}}},"responses":{"200":{"description":"Updated memory","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}},"403":{"description":"Cannot update a memory you did not create"},"404":{"description":"Memory not found or deleted"}}},"delete":{"operationId":"deleteMemory","x-openai-isConsequential":true,"summary":"Soft-delete a memory by ID (moves to trash)","description":"Delete a memory you previously wrote. Moves it to trash (recoverable from the dashboard). You can only delete memories you created (origin must match your vendor). Already-deleted memories return 404.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The memory UUID to delete"}],"responses":{"200":{"description":"Memory deleted (moved to trash)","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"},"id":{"type":"string"},"title":{"type":"string"}}}}}},"403":{"description":"Cannot delete a memory you did not create"},"404":{"description":"Memory not found or already deleted"}}}},"/agent/memories/{id}/versions":{"get":{"operationId":"getVersionHistory","x-openai-isConsequential":false,"summary":"Get edit history for a memory","description":"Returns all previous versions of a memory in reverse chronological order. Each version is a full snapshot captured before an edit. Use to review changes, audit edits, or compare past states.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The memory UUID"}],"responses":{"200":{"description":"Version history","content":{"application/json":{"schema":{"type":"object","properties":{"versions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"memory_id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"version_number":{"type":"integer"},"created_at":{"type":"string"}}}},"current_version":{"type":"integer","description":"The current version number (versions + 1)"}}}}}},"404":{"description":"Memory not found or not accessible"}}}},"/agent/memories/{id}/children":{"post":{"operationId":"writeChildMemory","x-openai-isConsequential":true,"summary":"Reply to an existing memory (write a child / threaded follow-up)","description":"Create a memory as a reply (child) of an existing parent — for resolutions, follow-ups, or status updates. Threads are one level deep (no replies-to-replies). Children inherit the parent's team sharing. Returns 404 if parent missing, 400 if parent is a child or in trash.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The parent memory UUID to reply under"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title","content","tags","allowed_vendors"],"properties":{"title":{"type":"string","maxLength":500,"description":"Short title for the reply"},"content":{"type":"string","maxLength":100000,"description":"The reply content"},"tags":{"type":"array","items":{"type":"string"},"maxItems":50,"description":"Tags for the reply"},"allowed_vendors":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":50,"description":"Which vendors can see this. Use ['*'] for all."},"memory_type":{"type":"string","enum":["semantic","episodic","procedural"],"description":"Memory type. Defaults to semantic."}}}}}},"responses":{"201":{"description":"Created child memory","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"parent_memory_id":{"type":"string","description":"The parent's UUID."},"shared_with_team_id":{"type":"string","nullable":true,"description":"Inherited from parent."},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}},"400":{"description":"Parent is a child (one-level), is trashed, or invalid request"},"404":{"description":"Parent memory not found or not owned"}}}},"/agent/memories/{id}/thread":{"get":{"operationId":"readThread","x-openai-isConsequential":false,"summary":"Read a memory and all its replies (full thread)","description":"Returns a parent memory plus every non-trashed reply in chronological order. Accepts either the parent's id or any child's id — the response is always rooted at the parent. Use this to see the full discussion or resolution history before replying, updating, or creating a new entry.\n","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Any memory UUID in the thread (parent or child)"}],"responses":{"200":{"description":"The thread (parent + children)","content":{"application/json":{"schema":{"type":"object","properties":{"parent":{"type":"object","description":"The thread's root memory (always the top-level parent).","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"shared_with_team_id":{"type":"string","nullable":true},"parent_memory_id":{"type":"string","nullable":true,"description":"Always null for the root."}}},"children":{"type":"array","description":"Replies in chronological order (oldest first).","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"},"parent_memory_id":{"type":"string","description":"The parent's UUID."}}}}}}}}},"404":{"description":"Memory not found, not owned, or thread root unreachable"}}}},"/agent/memories/search":{"post":{"operationId":"searchMemories","x-openai-isConsequential":false,"summary":"Search memories by text (returns full content)","description":"Full-text search across memory titles and content. Returns complete memory entries (with content) matching the search term. Use for finding specific information when you know keywords but not tags or IDs.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["term"],"properties":{"term":{"type":"string","minLength":1,"maxLength":500,"description":"Search term to match against title and content"},"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Max memories to return. Default: 10."}}}}}},"responses":{"200":{"description":"Matching memories with full content","content":{"application/json":{"schema":{"type":"object","properties":{"memories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"count":{"type":"integer"}}}}}}}}},"/agent/memories/list":{"post":{"operationId":"readMemories","x-openai-isConsequential":false,"summary":"Read recent memories (full content, bulk)","description":"Get the most recent memories with full content. Use limit to control how many. For discovering what exists without loading full content, use browseMemories instead.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":50,"description":"Max memories to return. Default: 10."}}}}}},"responses":{"200":{"description":"Recent memories with full content","content":{"application/json":{"schema":{"type":"object","properties":{"memories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"count":{"type":"integer"}}}}}}}}},"/agent/team/memories":{"get":{"operationId":"readTeamMemories","x-openai-isConsequential":false,"summary":"Read team shared memories","description":"Get memories shared with your team. Returns the team knowledge pool with author attribution. Only available if you belong to a team.\n","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50},"description":"Max team memories to return. Default: 20."},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0},"description":"Skip this many results for pagination. Default: 0."}],"responses":{"200":{"description":"Team shared memories","content":{"application/json":{"schema":{"type":"object","properties":{"team_memories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"memory_type":{"type":"string"},"author":{"type":"string"},"shared_at":{"type":"string"},"created_at":{"type":"string"}}}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"}}}}}},"404":{"description":"Not a member of any team"}}}},"/agent/team/share":{"post":{"operationId":"shareMemory","x-openai-isConsequential":true,"summary":"Share a memory with your team","description":"Share one of your personal memories with your team. The memory becomes visible to all team members via readTeamMemories. You must own the memory. Already-shared memories are handled gracefully (no error).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["memory_id"],"properties":{"memory_id":{"type":"string","description":"The UUID of your memory to share with the team"}}}}}},"responses":{"200":{"description":"Memory shared with team","content":{"application/json":{"schema":{"type":"object","properties":{"shared":{"type":"boolean"},"memory_id":{"type":"string"},"team_id":{"type":"string"}}}}}},"404":{"description":"Not a team member or memory not found"}}}},"/agent/memories/by-tag":{"post":{"operationId":"getMemoriesByTag","x-openai-isConsequential":false,"summary":"Get full-body memories filtered by tags","description":"Returns complete memory entries (with content) matching any of the given tags. Use this for council retrieval, topic-based audits, or any case where you need full memory bodies by topic. Supports pagination.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","items":{"type":"string"},"description":"Tags to filter by. Returns memories matching ANY of these tags."},"limit":{"type":"integer","minimum":1,"maximum":100,"description":"Max memories to return. Default: 20."},"offset":{"type":"integer","minimum":0,"description":"Skip this many results (for pagination). Default: 0."}}}}}},"responses":{"200":{"description":"Full-body memories matching the tags","content":{"application/json":{"schema":{"type":"object","properties":{"memories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"allowed_vendors":{"type":"array","items":{"type":"string"}},"memory_type":{"type":"string","description":"Memory type: semantic, episodic, or procedural"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"}}}}}}}}},"/agent/memories/browse":{"post":{"operationId":"browseMemories","x-openai-isConsequential":false,"summary":"Browse memory summaries (lightweight, no content)","description":"Returns memory metadata (title, tags, origin, timestamps) without full content. Use this to discover what memories exist, then use /query with specific IDs or tags to get AI responses grounded in relevant context. Supports pagination and search.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["filter"],"properties":{"filter":{"type":"object","description":"Filter memories. Options: {\"by\":\"all\"} for all memories, {\"by\":\"tags\",\"tags\":[\"project_state\"]} for tag filtering, {\"by\":\"search\",\"term\":\"authentication\"} for text search on title/content, {\"by\":\"ids\",\"ids\":[\"uuid1\",\"uuid2\"]} for specific IDs, {\"by\":\"origin\",\"origin\":\"cursor\"} for memories from a specific source tool (cursor, chatgpt, claude, user, dashboard).\n","required":["by"],"properties":{"by":{"type":"string","enum":["all","tags","ids","search","origin"]},"tags":{"type":"array","items":{"type":"string"}},"ids":{"type":"array","items":{"type":"string"}},"term":{"type":"string"},"origin":{"type":"string","description":"Source tool name. Required when by=origin. Values: cursor, chatgpt, claude, user, dashboard, or any configured vendor."}}},"limit":{"type":"integer","minimum":1,"maximum":200,"description":"Max memories to return. Default: 50."},"offset":{"type":"integer","minimum":0,"description":"Skip this many results (for pagination). Default: 0."}}}}}},"responses":{"200":{"description":"Paginated memory summaries (no content field)","content":{"application/json":{"schema":{"type":"object","properties":{"memories":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"origin":{"type":"string"},"memory_type":{"type":"string","description":"Memory type: semantic, episodic, or procedural"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"total":{"type":"integer","description":"Total matching memories (before pagination)"},"limit":{"type":"integer"},"offset":{"type":"integer"},"has_more":{"type":"boolean"}}}}}}}}},"/query":{"post":{"operationId":"queryMemory","x-openai-isConsequential":false,"summary":"Query AI with memory context","description":"AI answer grounded in selected memories. Use memory_filter to select which memories. Returns slim response (answer + metadata). Browse first, then query with tags or IDs.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["query","memory_filter"],"properties":{"query":{"type":"string","description":"The question to ask with memory context"},"memory_filter":{"type":"object","description":"Filter memories to include as context. Options: {\"by\":\"all\"} for all memories, {\"by\":\"tags\",\"tags\":[\"project_state\"]} for tag filtering, {\"by\":\"search\",\"term\":\"auth\"} for text search, {\"by\":\"ids\",\"ids\":[\"uuid1\"]} for specific IDs, {\"by\":\"origin\",\"origin\":\"cursor\"} for memories from a specific source tool. Prefer specific filters over \"all\" to avoid context size limits.\n","required":["by"],"properties":{"by":{"type":"string","enum":["all","tags","ids","search","origin"]},"tags":{"type":"array","items":{"type":"string"}},"ids":{"type":"array","items":{"type":"string"}},"term":{"type":"string"},"origin":{"type":"string","description":"Source tool name. Required when by=origin."}}},"limit":{"type":"integer","minimum":1,"maximum":50,"default":5,"description":"Max memories to include as context. Default: 5 for agents. Hard ceiling: 50. Use specific filters + low limit for best results."}}}}}},"responses":{"200":{"description":"AI response with metadata","content":{"application/json":{"schema":{"type":"object","properties":{"response":{"type":"string","description":"The AI model's answer"},"memories_used_count":{"type":"integer","description":"How many memories matched the filter"},"memories_included_in_prompt":{"type":"integer","description":"How many memories fit within the context budget"},"truncated":{"type":"boolean","description":"Whether some memories were omitted due to context size"},"estimated_tokens":{"type":"integer","description":"Estimated token count of the assembled prompt"},"vendor_filter":{"type":"string","nullable":true}}}}}}}}},"/whoami":{"get":{"operationId":"whoAmI","x-openai-isConsequential":false,"summary":"Check resolved identity from auth key","responses":{"200":{"description":"Caller identity","content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string"},"vendor":{"type":"string","nullable":true}}}}}}}}},"/agent/briefing":{"get":{"operationId":"getMemoryBriefing","x-openai-isConsequential":false,"summary":"Condensed snapshot of the user's memory state (call FIRST in a session)","description":"Returns a session briefing: identity, team membership, totals (personal/shared/team), top tag indexes, recent activity, open threads, and tagging conventions. Call FIRST in a session (or for a fresh snapshot) so you know what topics exist and what conventions to follow.\n","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","markdown"],"default":"json"},"description":"Response shape. JSON for programmatic use; markdown matches the MCP briefing."},{"name":"top_tags","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"Max tags per scope (default 30)."},{"name":"recency_days","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":90},"description":"Recency window for the \"active this week\" tag bucket (default 7)."},{"name":"active_threads","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":50},"description":"Max open threads to surface (default 5)."}],"responses":{"200":{"description":"The session briefing.","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string","nullable":true},"first_name":{"type":"string","nullable":true},"last_name":{"type":"string","nullable":true},"role":{"type":"string","nullable":true},"plan":{"type":"string","nullable":true},"team_id":{"type":"string","nullable":true},"team_name":{"type":"string","nullable":true},"team_role":{"type":"string","nullable":true},"team_member_count":{"type":"integer"}}},"totals":{"type":"object","properties":{"personal_memories":{"type":"integer"},"personal_memories_shared":{"type":"integer"},"team_pool_total":{"type":"integer"}}},"personal_tags":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"count":{"type":"integer"}}}},"team_tags":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"count":{"type":"integer"}}}},"recent_tags":{"type":"array","items":{"type":"object","properties":{"tag":{"type":"string"},"count":{"type":"integer"}}}},"active_threads":{"type":"array","items":{"type":"object","properties":{"memory_id":{"type":"string"},"title":{"type":"string"},"reply_count":{"type":"integer"},"last_activity_at":{"type":"string"},"shared_with_team":{"type":"boolean"}}}},"detected_conventions":{"type":"array","items":{"type":"string"}},"generated_at":{"type":"string"}}}},"text/markdown":{"schema":{"type":"string","description":"Markdown rendering of the briefing (when ?format=markdown)."}}}}}}}}}