Kemory · API
195 operations · 37 areas · generated from the service

The Kemory
API reference.

Every REST endpoint the service exposes, generated from the API's own schema rather than written by hand. Alongside it, the parts you cannot infer from a path: how a memory is compacted over time, and what actually happens behind the extension's enhance.

Base URL, auth and conventions

Every endpoint below is served by the Kemory API. Paths are given exactly as the service exposes them; prepend your deployment's origin.

ConcernDetail
Content typeapplication/json on request and response, except artifact upload (multipart) and artifact download (binary stream).
VersioningREST lives under /api/v1, apart from the health probes under /health and the LocalFS artifact stream at /artifacts/{token}. The MCP transport is at /mcp/v1. Discovery documents — and the OAuth dynamic-client-registration endpoint they advertise — sit at the root, where the specifications require them.
AuthA bearer token on Authorization, or an API key. See below.
Errors401 unauthenticated. A credential that resolves to no organisation is also rejected on some routes, but this is not enforced uniformly across the API today — do not rely on it either way. 403 authenticated but not permitted. 404 absent or outside your tenant, deliberately indistinguishable. Not uniformly, though — a number of by-id operations across memories, agents and permissions currently return 400 instead of 404 for a row that exists but is not yours, and the choice differs between verbs on the same resource. So do not read 400 as necessarily "your payload is malformed"; on a by-id call it may mean "gone, or not yours".

Three ways to authenticate

This table describes the hosted deployment. A deployment running the single-user identity provider instead — the default in the community compose file — accepts a single static API key — sent either way, since a non-JWT credential arriving in the Authorization header is still treated as a key — and rejects real JWTs.

CredentialHeaderUsed by
Keycloak RS256 bearerAuthorization: Bearer <jwt>Human users in the dashboard; the OAuth connector path.
HS256 bearerAuthorization: Bearer <jwt>Agents holding a signed service token.
API keyX-API-Key: <key> — or Authorization: Bearer <key>, which is what remote MCP clients configured for API-key auth actually sendRegistered agents; the usual choice for MCP.

20 of the operations below need no credential, each marked no auth in the tables. They are not only probes and public documents, so the categories are worth reading rather than assuming:

  • Health — five probes.
  • OAuth discovery — three .well-known documents, plus the dynamic client registration shim, which echoes a fixed pre-registered public PKCE client rather than creating one.
  • Artifact streams — three, carrying their own signature in the URL precisely so a binary can be fetched without a bearer.
  • Code-claiming endpoints — the pair claim, and the join claim and validate. The code is the credential, so these are unauthenticated by design and are the security-interesting members of this list: a pair claim self-registers an agent.
  • Telemetry ingest and the public plan catalogue.

The full list is generated from the same document as the endpoint tables, so it cannot fall behind the code:

MethodPathWhy it is open
GET/.well-known/kemory-cellsKemory Cells
GET/.well-known/oauth-authorization-serverOauth Authorization Server
GET/.well-known/oauth-protected-resourceOauth Protected Resource
GET/.well-known/oauth-protected-resource/mcp/v1Oauth Protected Resource Mcp
GET/.well-known/openai-apps-challengeOpenai Apps Challenge
GET/api/v1/artifacts/{artifact_id}/blobStream artifact binary (signed-URL auth — no bearer needed)
GET/api/v1/billing/plans/publicKemory's plan catalogue, unauthenticated
GET/api/v1/chats/{chat_id}/artifacts/{artifact_id}/blobStream a binary artifact body (signed-URL auth, no bearer needed)
POST/api/v1/join/{code}/claimClaim a Kemory bypass/referral code (no auth — the code is the credential)
GET/api/v1/join/{code}/validateValidate a Kemory bypass/referral code (no auth — the code is the credential)
POST/api/v1/pair/{code}/claimSelf‑register an agent using a pair code (called by the AI)
POST/api/v1/telemetryIngest an opt-in anonymous CLI telemetry event
GET/artifacts/{token}Stream a LocalFS artifact by signed token
GET/health/deepDeep Health
GET/health/historyHealth History
GET/health/liveLiveness
GET/health/pipelinePipeline Health
GET/health/readyReadiness
GET/health/retrievalRetrieval Health
POST/oauth/registerOauth Register

A credential is not the whole access boundary. Some Analytics and Consolidation operations additionally require an internal-staff identity and are not reachable with an API key or an agent token, however valid.

Scoping

Most tenant-scoped ORM reads have WHERE org_id = <caller's org> injected by a SQLAlchemy do_orm_execute listener, acting as a safety net over the filters handlers also apply. It is a net, not a universal guarantee: it covers registered models, SELECTs, and statements that expose a mapped entity — raw SQL and unmapped statements are the handler's own responsibility.

Memories default to owner-private, but for two of the four visibilities visibility is access control, not a label: a memory written org-public is readable by every user in the organisation, and one written team by every member of that team. So "scoped to their owner" is the default, not an invariant.

agent-private is the opposite trap — it is only a label. The tenancy filter treats it exactly like user-private, and no read path narrows it to the writing agent, so it does not hide a memory from the same user's other agents. Do not use it as an isolation boundary.

shared is the default namespace name, not an access tier — it gets no special handling in the gatekeeper or the tenancy filter. Agents authenticate as their user, so any namespace the user can reach is reachable by that user's agents; whether a given agent actually reads it is then decided by its own gatekeeper rules.

Compaction — the tier ladder

A memory is not stored once and left alone. It is served back at several levels, each a cheaper reading of the same content.

Only three of the rows below are states an individual memory occupies: L1, L2 and L3.1. Those are reported on the memory's own compression_tier response field — the supported surface, in preference to the internal metadata._compression_tier key — and the same three values work as a search filter. L1 is the default: nothing writes it, the key is simply absent until the pipeline promotes the memory. The remaining rows are not per-memory states at all, and live elsewhere entirely.

TierWhat it isTriggerStored where
L1The raw observation as written — source of truth. Searchable (FTS + vector).Default state; no tier key present.The memory row
L2AAAK field-aliased byte encoding — computed and measured at write time, then discarded. Only the tier, the achieved ratio and a timestamp persist; mode=aaak re-encodes on demand.Asynchronously after write.The memory row
L2.1Rolling session digest — readable digest of older context plus the latest raw exchanges. See below.Once a session exceeds the raw tail.Its own session-digest table
L3Narrative prose, in three flavours: per namespace, per session, and cumulative as of a session boundary. Below 5 source memories it is not prose at all — see the note under the table.Namespace: ≥2 memories · session: ≥1 · cumulative: ≥2 up to the boundary.Namespace flavour: a column on the namespace policy. Session and cumulative: their own session-summary table.
L3.1LLM concept synthesis — clusters and directional merges, written back as content_type='concept' rows. Searchable, and hit by ordinary recall.≥3 memories, ≥1 cluster.New memory rows, and the namespace policy's summary column — which is where the degraded L3.1-raw marker appears
L4L3.1 plus Cognition OS graph entities, merged per request. Never stored.On request. CogOS availability only decides whether the graph entities are populated — the response is returned either way, with a flag saying which.Not stored
L5Namespace merge detection. Advisory only.Last stage of every compression run, where the enterprise plugin stage is loaded. It is controlled by an opt-out flag (on unless disabled), and the shipped community compose file disables it — so a stock community deployment produces no merge suggestions, while a self-hosted one not using that file will.An advisory list on the namespace policy

Read a namespace at a chosen level with GET /api/v1/namespaces/{namespace}/compressed: mode takes raw (L1), aaak (L2), concept (L3.1) or cognition (L4), and merge_mode selects the latest state or the full history. L3 narrative is not a /compressed mode — it is read through the namespace and session summary endpoints.

Below five memories, L3 is not prose

All three L3 flavours require at least 5 source memories to call a model. Below that they emit a deterministic, LLM-free bullet list of the source memories instead — so no summary tier guarantees prose.

Only the namespace flavour says so in its tier. The namespace summary tags the fallback L3-extractive. The session and cumulative rollups do not: they report the literal L3 whether the text is prose or a bullet list. A client that switches on the tier to decide how to render will get this wrong on session summaries — do not treat L3 on a session rollup as a promise of prose.

Tier strings a caller may encounter include L3, L3-extractive, L3.1, L3.1-raw, L3.1-chat, and on session digests L2.1 and L2.1-extractive. Some read paths also synthesise a value when the stored column is empty. Treat the set as open. Match on the exact base before the first hyphen, and on the -extractive / -raw suffix to detect a degraded variant — rather than switching on an exhaustive list. Do not match a bare L3 prefix: it also catches L3.1, which is concept synthesis, not narrative prose.

L3.1-raw is the degraded marker: a cluster formed but synthesis did not produce usable output — whether the backend was unreachable or simply returned nothing useful — so the stored text is unsynthesised source material rather than prose.

L5 deliberately excludes siblings

L5 compares this namespace's summary against the same user's other namespace summaries, and deliberately skips same-prefix siblings: project:alpha and project:beta are structurally distinct by design, not accidental duplicates, so they are never proposed for merge however similar their prose. A pair is flagged only above a cosine threshold and within a content-date window, and the result is advisory — nothing merges on its own.

L5 is not the top of the ladder. Despite the number it is a background duplicate-namespace detector, not a richer read. The cross-namespace "who is this user" paragraph is GET /api/v1/user/context?depth=l4.

"L4" labels two different reads. In this table it means concepts plus graph entities for one namespace. On user context, depth=l4 means a synthesis pass across namespace summaries. They share a name and a number and fail in different ways — read the one you are actually calling.

AAAK is a storage, transport and diagnostic dialect — not context compression. It saves bytes against compact JSON while often costing prompt tokens against readable text, and off-the-shelf gzip beats it losslessly by a wide margin. Reaching for aaak to shrink a prompt is a misreading of the tier. Semantic compaction is what reduces what a model must read: L3/L3.1, and L2.1 for a live session.

Why a namespace may not have summarised

Several gates guard L3, and they are the usual answer to "why has this namespace not summarised yet". Two are similarity checks, and they are genuinely different tests, often conflated:

  • Novelty — is the new memory a near-duplicate of a memory already in the namespace? Above a high cosine bar the run is skipped.
  • Coverage — is the new memory already represented in the existing summary, compared against the summary's own embedding at a lower bar?

Either can skip a run on its own, and neither means anything is broken: a namespace whose new material restates what is already summarised is correctly left alone rather than paying for a model call to say it again.

Note also that the sub-five-memory bullet-list fallback runs before any model call, and on a session rollup it is still tiered L3. On a session rollup, an L3 tier is therefore not evidence that a model produced the text. (The namespace flavour does distinguish the two — it tags the fallback L3-extractive.)

Not every empty summary is a gate doing its job. L3 also depends on the deployment's model configuration, and the write path is not the only route that produces summaries — some are generated by background and warm-up paths with different preconditions. If a namespace has no summary and the similarity gates above do not explain it, treat it as a threshold or configuration question — a namespace below the minimum memory count simply has nothing to summarise — and check docs/memory-management.md in the repository rather than inferring the cause from the tier alone.

L2.1 — the rolling session digest

This is the service most often described as "the last few messages plus a summary", and the one to reach for when the problem is prompt-window pressure during a live session rather than recall across the vault.

Kemory keeps the latest few exchanges verbatim — three by default — and compacts everything older into a single readable, token-budgeted digest covering the current objective, decisions, constraints and open loops. The raw tail is a per-call parameter clamped to 1–10 exchanges; 3 is the default, so the digest first appears once a session runs past its raw tail. It is deliberately prose rather than AAAK, because it is prompt-facing — the tier that exists to be read by a model is the one that must not be encoded for bytes. If no model backend is reachable, or the call fails or returns nothing, a deterministic extractive fallback runs instead.

Nothing is lost, only deferred

The digest carries retrieval hooks and the source ids behind its sections and facts, so an agent needing the exact wording of an older exchange can drill back to it on demand rather than being told a compressed approximation is all that survives. That is the difference between this and truncating a transcript.

ToolWhat it does
kemory_get_session_contextThe rolling digest plus the latest raw exchanges for one session.
kemory_rehydrate_session_sourcesDrill from a digest hook back to the exact raw sources behind it.

MCP-only. There is no REST endpoint for the session digest — it is reached through the two tools above over POST /mcp/v1. A REST client wanting session context has to go through MCP. It is also not searchable: the digest is retrieved by session, not found by query.

Search summary — the service behind enhance

Not a separate service, which is why it is hard to find: it is POST /api/v1/search/unified with the summary opted in.

The call returns top ranked hits across memories, chats and text-native files and, when asked, a short narrative summary written over those hits.

As of writing, the Kora browser extension's enhance is built on it (extension behaviour described here lives in a separate repository, so treat it as how the client uses the endpoint today rather than part of the API contract): it searches on the user's draft plus recent conversation turns, takes the top handful, and appends them to the prompt as a delimited, provenance-tagged context block alongside the summary. Nothing rewrites the draft — the model is given context and left to decide.

The invariant that matters

The summary is written only over hits that were returned, and its sources array lists the ids it drew on. Treat that as a property of how the summary is produced rather than a guarantee about the response in your hand — see the caching caveat below, which is the case where it does not hold. This is what stops the summary asserting something the user cannot click through and verify — so a client that filters results after the fact must drop the summary too, or it outlives the hit it was describing. Note this is a contract the caller must honour, not something enforced for you: the constraint is applied when the summary is written, not re-checked afterwards.

The summary is opt-in because it costs a model call, and a caller that only needs a count or a list should not pay for prose.

Summaries are briefly cached per user and query — and the cache key is only the user and the query text. It does not include the result filters. So the same query issued with a narrower type filter or a smaller limit can be served a cached summary whose sources reference hits that are not in the response you are holding. If you rely on the sources-are-a-subset property, request without narrowing, or ignore the summary when you do narrow.

Degrading honestly

If the summary cannot be produced, the response carries results with no summary rather than failing. Treat it as decoration over the results, never as the result itself. A client may also fall back to a plain memory search when the unified endpoint is unavailable — in which case there is no summary at all, and the context block is hits only.

User context — what the vault knows about someone

GET /api/v1/user/context returns a cross-namespace summary for the authenticated user, assembled from the compressed tiers rather than by reading every memory. It is the fast "catch me up" read that agents call at the start of a session, and it takes a depth so a caller can ask for a cheaper or richer answer.

At depth=l4 it runs one synthesis pass across the per-namespace summaries. That pass is not stored — it is computed per request — and it degrades gracefully: if the model call fails, the response comes back without the synthesised layer rather than erroring. Treat the summary as an optional enrichment over the namespace data, not a guaranteed field.

There is also an entitlement gate ahead of the model call. It keys on the caller's resolved entitlement feature, not on a plan name: where that feature resolves to the basic tier, the request is downgraded to depth=l3 and answered with a degraded block, so the synthesis never runs. If entitlements fail to resolve at all the gate does not fire and the full pass runs. Both directions surprise people debugging a missing — or unexpectedly present — synthesis layer.

GET /api/v1/user/profile is the narrower, persisted view: static preferences plus a dynamic part maintained as memories accumulate.

Memories 24

Create, read, search and version memories. The core surface — everything else is either feeding this or reading from it.

MethodPathWhat it does
POST/api/v1/memoriesCreate a memory
POST/api/v1/memories/aggregateAggregation queries over memories (count / sum / list / duration)
POST/api/v1/memories/bulkBulk-create memories (backfill / import)
POST/api/v1/memories/bulk-movePreview or apply an audited memory namespace/tag move
GET/api/v1/memories/exportExport all active memories as a streamed JSON download
POST/api/v1/memories/facetsCount Memory Explorer facets exactly
POST/api/v1/memories/purgePurge (soft-delete) all memories, optionally scoped to a namespace
POST/api/v1/memories/searchSearch memories
DELETE/api/v1/memories/{memory_id}Delete a memory
GET/api/v1/memories/{memory_id}Get a memory
PUT/api/v1/memories/{memory_id}Update a memory
GET/api/v1/memories/{memory_id}/historyGet memory provenance history
POST/api/v1/memories/{memory_id}/rateRate a recalled memory (KMV-ANA-06) — thumbs up/down + reason
GET/api/v1/memories/{memory_id}/similarFind cosine-similar memories (dedup affordance)
GET/api/v1/namespacesList namespaces
GET/api/v1/namespaces/hygieneCount exact singleton and two-item namespace tail
GET/api/v1/namespaces/{namespace}/compressedMulti-level memory read (L1 raw / L2 AAAK / L3.1 concept / L4 cognition)
PUT/api/v1/namespaces/{namespace}/descriptionSet a namespace's human-readable description (S9N-6188)
POST/api/v1/namespaces/{namespace}/merge-into/{target}Merge one namespace into another (memories, chats, artifacts, policy)
POST/api/v1/namespaces/{namespace}/recomputeForce an on-demand consolidated-summary recompute (S9N-6188)
GET/api/v1/namespaces/{namespace}/sessions/{session_id}/summaryGet per-session L3 rollup (session + cumulative-to-this-point)
GET/api/v1/namespaces/{namespace}/summaryGet consolidated cross-session summary for a namespace
GET/api/v1/namespaces/{namespace}/tagsList a namespace's second-tier segments (S9N-6612)
GET/api/v1/namespaces/{namespace}/timelineUnified time-ordered stream of a namespace's chats + memories (S9N-6392)

User Context 11

Cross-namespace summaries of who the caller is and what the vault knows, plus the account-level privacy controls (consent, encryption opt-in, crypto-shred).

MethodPathWhat it does
DELETE/api/v1/user/chat-dataCrypto-shred: permanently erase the authenticated user's chat data (this org)
GET/api/v1/user/consentsList the caller's recorded policy acceptances
POST/api/v1/user/consentsRecord acceptance of a policy document (idempotent per user+document+version)
GET/api/v1/user/contextCross-namespace context summary for the authenticated user
GET/api/v1/user/encryption-statusChat-content at-rest encryption coverage for the authenticated user
POST/api/v1/user/encryption/enableOpt in: enable chat-content encryption at rest for the authenticated user
POST/api/v1/user/erasure-intentDeclare intent to erase — step 1 of 2 for the crypto-shred endpoints
DELETE/api/v1/user/memory-dataCrypto-shred: permanently erase the authenticated user's memory data (this org)
GET/api/v1/user/profilePersisted user profile (static preferences + dynamic recent activity)
GET/api/v1/user/telemetry-preferenceKMV-ANA-13 — the caller's telemetry opt-in/out preference
PUT/api/v1/user/telemetry-preferenceKMV-ANA-13 — set the caller's telemetry opt-in/out preference

Consolidation 6

Namespace consolidation policy and the stats behind it — the tier machinery described above, exposed for inspection and manual runs.

MethodPathWhat it does
POST/api/v1/admin/consolidate-allRun consolidation across every active namespace (admin)
GET/api/v1/namespaces/consolidation-statsConsolidation stats across all namespaces
POST/api/v1/namespaces/{namespace}/consolidateTrigger an ad-hoc consolidation run for a namespace
GET/api/v1/namespaces/{namespace}/consolidation-statsConsolidation stats for a single namespace
GET/api/v1/namespaces/{namespace}/policyRead the consolidation policy for a namespace
PUT/api/v1/namespaces/{namespace}/policyCreate or update the consolidation policy for a namespace

Enrichment 3

Post-write enrichment of individual memories (entities, structure).

MethodPathWhat it does
POST/api/v1/enrichment/batchEnrich all pending memories
POST/api/v1/memories/{memory_id}/enrichEnrich a single memory
GET/api/v1/memories/{memory_id}/enrichmentGet enrichment results for a memory

Relations 4

Explicit relations between memories, detected conflicts, and the forgetting log.

MethodPathWhat it does
GET/api/v1/forgetting-logNewest-first log of forgets, expiries and supersessions
POST/api/v1/memories/resolve-conflictResolve a conflict: loser superseded by winner
GET/api/v1/memories/{memory_id}/relationsList a memory's typed relations
POST/api/v1/memories/{memory_id}/relationsAssert a typed relation from this memory to a target

Projects 2

Explicit and implicit project aliases over namespaces.

MethodPathWhat it does
GET/api/v1/projectsList projects (explicit rows + implicit project:* namespaces)
POST/api/v1/projectsCreate an explicit project alias

AI Chats 13

Captured conversations from ChatGPT, Claude, Gemini, Perplexity and Manus — upsert, list, classify and move.

MethodPathWhat it does
GET/api/v1/chatsList captured chats with filters
POST/api/v1/chatsIdempotent upsert of a captured chat (+ turns + artifacts)
POST/api/v1/chats/bulkBulk idempotent upsert of captured chats (retro-sync / import)
DELETE/api/v1/chats/{chat_id}Soft-delete a chat
GET/api/v1/chats/{chat_id}Get one chat, optionally with turns + artifacts
POST/api/v1/chats/{chat_id}/artifacts/uploadUpload a binary artifact (file / audio / video / image) for a turn
GET/api/v1/chats/{chat_id}/artifacts/{artifact_id}/blobno authStream a binary artifact body (signed-URL auth, no bearer needed)
POST/api/v1/chats/{chat_id}/classifySuggest destination namespaces for a chat based on its content
GET/api/v1/chats/{chat_id}/contextStored session digest for one captured chat (read-only, no regeneration)
POST/api/v1/chats/{chat_id}/moveMove a chat to a different namespace
PATCH/api/v1/chats/{chat_id}/project-metadataEnrich project identity without changing stored turns
GET/api/v1/chats/{chat_id}/timelineUnified cross-surface timeline for one chat (KMV-WA-E3-S2)
POST/api/v1/chats/{chat_id}/turns:batchAppend (or upsert by source_turn_id) a batch of turns

AI Chats — Merge 6

Merging chats into a shared namespace, splitting them out again, and the full assignment audit trail.

MethodPathWhat it does
POST/api/v1/chats/bulk-mergeMerge many chats into one namespace at once
POST/api/v1/chats/{chat_id}/mergeMerge a chat into a target namespace (sets merged_namespace)
GET/api/v1/chats/{chat_id}/namespace-historyFull chat↔namespace assignment audit for one chat
POST/api/v1/chats/{chat_id}/split-outMake a chat standalone with a unique namespace (KMV-CMERGE-S08)
GET/api/v1/chats/{chat_id}/suggestionsTop-N merge candidates for a chat
POST/api/v1/chats/{chat_id}/unmergeClear merged_namespace; restore original_namespace as active

AI Chats — Mappings 4

User overrides that pin a chat to a namespace.

MethodPathWhat it does
GET/api/v1/chat-mappingsList own chat namespace mappings
POST/api/v1/chat-mappingsCreate a chat namespace mapping override
DELETE/api/v1/chat-mappings/{mapping_id}Delete a chat namespace mapping
PATCH/api/v1/chat-mappings/{mapping_id}Update a chat namespace mapping

artifacts 8

Binary attachments on chat turns — files, audio, video, images.

MethodPathWhat it does
POST/api/v1/artifacts/uploadUpload a file to a namespace or memory (project files)
DELETE/api/v1/artifacts/{artifact_id}Delete an artifact
GET/api/v1/artifacts/{artifact_id}Get artifact metadata
GET/api/v1/artifacts/{artifact_id}/blobno authStream artifact binary (signed-URL auth — no bearer needed)
GET/api/v1/memories/{memory_id}/artifactsList artifacts attached to a memory
POST/api/v1/memories/{memory_id}/artifacts/uploadUpload a file attached to a memory
GET/api/v1/namespaces/{namespace}/artifactsList artifacts for a namespace
GET/artifacts/{token}no authStream a LocalFS artifact by signed token

Agents 10

Registered clients that hold credentials against the vault: MCP clients, CLI installs, the browser extension.

MethodPathWhat it does
GET/api/v1/agentsList user's agents
POST/api/v1/agentsRegister a new agent
DELETE/api/v1/agents/{agent_id}Delete a revoked agent (or revoke-and-delete with ?force=true)
GET/api/v1/agents/{agent_id}Get agent details
PATCH/api/v1/agents/{agent_id}Rename an agent's friendly display name
POST/api/v1/agents/{agent_id}/approveApprove a pending agent
POST/api/v1/agents/{agent_id}/revokePermanently revoke an agent
POST/api/v1/agents/{agent_id}/rotate-keyRotate the API key for an agent
POST/api/v1/agents/{agent_id}/suspendSuspend an agent
POST/api/v1/agents/{agent_id}/tokenGenerate JWT access token for an agent

Extension Keys 4

Credentials issued specifically to the Kora browser extension.

MethodPathWhat it does
GET/api/v1/extension/keysList own extension keys
POST/api/v1/extension/keysMint (or rotate) a Chrome Extension API key
DELETE/api/v1/extension/keys/{key_id}Revoke an extension key
PATCH/api/v1/extension/keys/{key_id}Rename a device (edit its label) — S9N-6326

Pair 4

The quick-connect flow: a short-lived code exchanged for an API key.

MethodPathWhat it does
GET/api/v1/pair/setup/{client_id}Per-client MCP setup block (pre-claim, placeholder key) — S9N-6314
POST/api/v1/pair/startMint a short‑lived pair code for quick‑connect setup
POST/api/v1/pair/{code}/claimno authSelf‑register an agent using a pair code (called by the AI)
GET/api/v1/pair/{code}/statusPoll a pair code's claim status (originator only)

MCP Server 5

The Model Context Protocol transport. POST /mcp/v1 is the live endpoint; the per-verb paths are deprecated.

MethodPathWhat it does
POST/mcp/v1MCP Streamable HTTP transport (JSON-RPC 2.0)
POST/mcp/v1/prompts/getdeprecated[DEPRECATED] Fetch a versioned MCP prompt by name (use POST /mcp/v1)
POST/mcp/v1/prompts/listdeprecated[DEPRECATED] List available MCP prompts (use POST /mcp/v1)
POST/mcp/v1/tools/calldeprecated[DEPRECATED] Call an MCP tool (use POST /mcp/v1)
POST/mcp/v1/tools/listdeprecated[DEPRECATED] List available MCP tools (use POST /mcp/v1)

MCP 6

Connected MCP client status.

MethodPathWhat it does
GET/api/v1/mcp/clientsList Mcp Clients
POST/api/v1/mcp/clients/{client_slug}/connectStart Mcp Connect
POST/api/v1/mcp/clients/{client_slug}/revoke/completeComplete Mcp Revoke
POST/api/v1/mcp/clients/{client_slug}/revoke/startStart Mcp Revoke
GET/api/v1/mcp/org-selectionGet Mcp Org Selection
PUT/api/v1/mcp/org-selectionPut Mcp Org Selection

OAuth discovery 4

RFC 9728 protected-resource and authorization-server metadata, plus the dynamic client registration shim.

MethodPathWhat it does
GET/.well-known/oauth-authorization-serverno authOauth Authorization Server
GET/.well-known/oauth-protected-resourceno authOauth Protected Resource
GET/.well-known/oauth-protected-resource/mcp/v1no authOauth Protected Resource Mcp
POST/oauth/registerno authOauth Register

Cells directory 1

Unauthenticated residency-cell directory — which cells exist and their public hosts, so clients route to the right region without a hardcoded list.

MethodPathWhat it does
GET/.well-known/kemory-cellsno authKemory Cells

Identity 2

Who the bearer token belongs to.

MethodPathWhat it does
GET/api/v1/meIdentity, organisation, and team membership for the caller
GET/api/v1/me/orgsOrganisations the caller can switch between (ADR-012)

Permissions 5

Per-agent, per-namespace permission grants.

MethodPathWhat it does
GET/api/v1/permissionsList permission rules
POST/api/v1/permissionsCreate a permission rule
DELETE/api/v1/permissions/{rule_id}Delete a permission rule
GET/api/v1/permissions/{rule_id}Get a permission rule
PUT/api/v1/permissions/{rule_id}Update a permission rule

Gatekeeper 3

Ordered rules evaluated on every access decision — lower priority number first, first match wins.

MethodPathWhat it does
GET/api/v1/gatekeeper/consentList JIT consent requests
POST/api/v1/gatekeeper/consent/{consent_id}/resolveResolve a JIT consent request
POST/api/v1/gatekeeper/evaluateEvaluate a permission request

Teams 5

Kemory's own teams and membership. Independent of Core_Backend's teams; there is no sync between them.

MethodPathWhat it does
GET/api/v1/orgs/{org_id}/teamsList teams in an org
POST/api/v1/orgs/{org_id}/teamsCreate a team in an org
POST/api/v1/teams/{team_id}/membersAdd a member to a team
DELETE/api/v1/teams/{team_id}/members/{user_id}Remove a member from a team
PATCH/api/v1/teams/{team_id}/members/{user_id}Update a member's role / can_write flag

Graph 2

The access graph — who can reach what.

MethodPathWhat it does
GET/api/v1/graph/access-mapGet agent-memory-namespace access graph
GET/api/v1/graph/memory-graphMemory graph: memories as nodes, typed relations as edges

Audit & Governance 4

Audit trail over reads and writes.

MethodPathWhat it does
GET/api/v1/audit/logsQuery audit logs
GET/api/v1/audit/rate-limitCheck rate limit status
POST/api/v1/audit/validate-writeValidate a write operation
GET/api/v1/audit/verifyVerify audit chain integrity

Dashboard 6

Aggregates backing the dashboard home.

MethodPathWhat it does
GET/api/v1/dashboard/embedding-coverageEmbedding coverage for the calling user's own rows
GET/api/v1/dashboard/memories-by-agentPer-agent memories-written series (Analytics chart 4)
GET/api/v1/dashboard/overviewDashboard overview — counts, services, and recent activity
GET/api/v1/dashboard/search-latencyPer-day search latency p50/p95 (Analytics chart 2)
GET/api/v1/dashboard/summary-skipsWeekly optimiser summary-skip count (Analytics chart 6)
GET/api/v1/dashboard/trendsDashboard trends — per-day counts for tile sparklines + deltas

Analytics 21

Storage, usage and quality analytics.

MethodPathWhat it does
GET/api/v1/analytics/activationKMV-ANA-06 — activation flag/date for the caller's own account
GET/api/v1/analytics/activation/cohortKMV-ANA-06 — median time-to-useful-recall / time-to-cross-surface, by signup week
POST/api/v1/analytics/activation/stagesOnboarding-stage timestamps for a batch of accounts (admin users list)
GET/api/v1/analytics/agent-activityAgent activity over time — reads/writes/denied per day
GET/api/v1/analytics/exec-dashboardKMV-ANA-12 — executive dashboard: health scorecard + segmentation + usage distribution + savings
GET/api/v1/analytics/exec-dashboard/platformKMV-ANA-12 — the exec dashboard pooled across EVERY org (platform scope)
GET/api/v1/analytics/recall/memoriesS9N-7207 — per-memory recall counts, or the memories never recalled in the window
GET/api/v1/analytics/recall/summaryS9N-7207 — recall volume and TOKEN COST for the caller's own account
GET/api/v1/analytics/savingsKMV-ANA-08 — cumulative modelled savings for the caller's own account, compaction vs routing
GET/api/v1/analytics/scorecardKMV-ANA-10 — the 5/5/5 scorecard: lead, lag, and health indicators, always together
GET/api/v1/analytics/storageStorage analytics — memories by tier + type, approximate size, totals
GET/api/v1/analytics/usage-ladderKMV-ANA-07 — per-day highest usage level reached, for the caller's own account
GET/api/v1/analytics/usage-ladder/depth-frequencyKMV-ANA-12 — depth (level reached) x frequency (active days) grid, cohorted by account age
GET/api/v1/analytics/usage-ladder/distributionKMV-ANA-07 — active-days histogram at a given level, cohorted by account age
GET/api/v1/analytics/usage-ladder/power-usersKMV-ANA-07 — power-user ratio (>=5/7 active) and dormant-connected ratio
GET/api/v1/analytics/usage-ladder/progressionKMV-ANA-07 — % of accounts reaching usage_L1/usage_L2 within 30 days of first connect
GET/api/v1/analytics/value-modeKMV-ANA-11 — continuity / cross-AI / builder classification for the caller's own account
GET/api/v1/analytics/value-mode/activationKMV-ANA-11 — activation rate segmented by value mode
GET/api/v1/analytics/value-mode/activation/platformKMV-ANA-11 — activation rate by value mode, pooled across EVERY org
GET/api/v1/analytics/value-mode/segment-mixKMV-ANA-11 — org-wide segment mix, insurance-retained vs genuinely-dormant split
GET/api/v1/analytics/value-mode/segment-mix/trendKMV-ANA-11 — segment mix over time, one snapshot per week

Usage 1

Plan usage summary.

MethodPathWhat it does
GET/api/v1/usage/summaryMetered usage for the authenticated user

Telemetry 1

Opt-in CLI beacon.

MethodPathWhat it does
POST/api/v1/telemetryno authIngest an opt-in anonymous CLI telemetry event

Health 6

Liveness, readiness and deep dependency health.

MethodPathWhat it does
GET/health/deepno authDeep Health
GET/health/historyno authHealth History
GET/health/liveno authLiveness
GET/health/pipelineno authPipeline Health
GET/health/readyno authReadiness
GET/health/retrievalno authRetrieval Health

billing 7

Kemory plans and checkout. Proxies Core_Backend.

These endpoints forward to Core_Backend. Kemory serves the route; the behaviour behind it is owned elsewhere.

MethodPathWhat it does
POST/api/v1/billing/checkoutStart a Stripe hosted Checkout for a Kemory plan
GET/api/v1/billing/plansKemory's public plan catalogue
GET/api/v1/billing/plans/publicno authKemory's plan catalogue, unauthenticated
GET/api/v1/billing/portalStripe Billing Portal URL for self-service billing
GET/api/v1/billing/subscriptionThe caller's active Kemory subscription, if any
GET/api/v1/billing/transactionsThe org's Kemory invoice history
GET/api/v1/billing/usagePlan caps and how much of them the caller has used

referral 2

Referral codes. Proxies Core_Backend.

These endpoints forward to Core_Backend. Kemory serves the route; the behaviour behind it is owned elsewhere.

MethodPathWhat it does
POST/api/v1/referral/inviteInvite someone to Kemory with the caller's referral link
GET/api/v1/referral/meThe caller's Kemory referral link, stats and activity

residency 3

Data-residency region selection. Proxies Core_Backend.

These endpoints forward to Core_Backend. Kemory serves the route; the behaviour behind it is owned elsewhere.

MethodPathWhat it does
GET/api/v1/residencyGet Residency
POST/api/v1/residencyChoose Residency
GET/api/v1/residency/cellGet Residency Cell

join 2

Waitlist-bypass claim.

MethodPathWhat it does
POST/api/v1/join/{code}/claimno authClaim a Kemory bypass/referral code (no auth — the code is the credential)
GET/api/v1/join/{code}/validateno authValidate a Kemory bypass/referral code (no auth — the code is the credential)

Ask 1

MethodPathWhat it does
POST/api/v1/askSynthesized answer over retrieved memory, with its sources

Kora 1

MethodPathWhat it does
POST/api/kora/v1/chat/orchestrated/streamAsk Kora — relays core-ai-backend's orchestrated chat stream

Notifications 6

MethodPathWhat it does
GET/api/v1/notificationsList the caller's notifications
GET/api/v1/notifications/preferencesPer-family notification preferences
PUT/api/v1/notifications/preferencesUpdate notification preferences
POST/api/v1/notifications/read-allMark all as read, except Action required
GET/api/v1/notifications/unread-countUnread count for the header bell
POST/api/v1/notifications/{notification_id}/readMark one notification as read

OpenAI plugin verification 1

MethodPathWhat it does
GET/.well-known/openai-apps-challengeno authOpenai Apps Challenge

Keeping this page honest

The endpoint tables on this page are generated from the running service's own OpenAPI document by scripts/generate_api_reference.py in the Kemory repository. They are not maintained by hand, because a reference covering this many operations drifts the moment someone adds a route — and a docs page that is quietly wrong is worse than no page at all, since it is trusted.

Regenerate after any route change. The narrative sections above are hand-written and describe behaviour a schema cannot express; they need a human when the behaviour changes.