NewRelease 0.12.3 is out: Engine v0.12.3, Dashboard 0.5.2, Helm 0.12.3, the four SDKs, CLI 0.8.2 and MCP 0.12.3Release 0.12.3 is outSee what's new →

REST API reference

This page lists every HTTP route a Dakera v0.12.3 server exposes, grouped by area, with the request fields, status codes and permission scopes that matter when you call it directly. It is for developers writing their own client or checking what an SDK sends; if you use a language SDK or the MCP server, treat it as the reference behind those.

Authentication is on by default. Every route except /health, /health/live, /health/ready and /metrics needs an API key, sent as Authorization: Bearer <key> or X-API-Key: <key>. With authentication on and no key configured, the server refuses to start; set DAKERA_ROOT_API_KEY to create the first key. Since v0.12 the gRPC port takes the same keys as call metadata.

New in v0.12.0 — Capability discovery (GET /v1/capabilities), per-request lang, rerank_candidates and rerank_report, opt-in attachments, speech to text, image indexing and records, enforced quotas (413), keyring-based encryption rotation, backup encrypt / compression, and one JSON error shape. Feature guides: Multilingual search, Search and ranking, Multimodal memory, Records and multi-vector, Operations.
New in v0.12.2 — POST /v1/agents, GET /v1/auth/whoami, PATCH on keys, prefix patterns in key grants and a rotation grace period; session auto-end with POST /v1/sessions/{id}/touch and idle_timeout_secs; an opt-in content_preview_chars on the graph and memory listings; include_derived; /admin/derivations/*; unavailable on node-wide endpoints; capabilities version 2. Stricter validation on every write path (400, the message names the field and the rule). Every change: Changelog.
New in v0.12.3 — Document import (PDF, DOCX, HTML, Markdown, text); on recall neighborhood_mode, include_summaries, rank_score and context_memories; event_time on store and batch store; restorable deduplication and consolidation (/v1/memory/deduplicated); warnings for ignored request fields; 429 with Retry-After on overload. POST /ops/shutdown needs super_admin, and four admin requests answer 422 to unknown fields. Every change: Changelog.
Base URL — Replace localhost:3000 with your server's address (e.g. http://<YOUR_SERVER_IP>:3000). Application routes live under /v1/; health, metrics, /ops and /admin routes are unversioned (admin routes are also served under /v1/admin).

Health

MethodPathAuthDescription
GET/healthNoReturns server status and version, plus degraded components and config_warnings. While models load it answers 503 with "status": "starting", a reason and per-file download progress
GET/health/liveNoLiveness: 200 as soon as the port is bound, even while models are still loading (since v0.12 the port binds before models load)
GET/health/readyNoReadiness: 200 once the embedding model is loaded and storage answers; 503 with progress before that
GET/metricsNoPrometheus metrics

GET /health answers status (healthy or degraded), version, build_sha, unreadable_records and corrupt_records, degraded (every degraded component with a reason; always present), config_warnings (configuration the node started with although it is not what it should be; informational, never makes the node degraded), embed_migration (progress of the one-time re-embed of stored memories) and, in a cluster, clock_ahead_ms while this node's clock is too far ahead of its peers. While starting it answers 503 with "status": "starting", a reason and downloads (each model file with received_bytes and total_bytes). Reasons never contain file paths or credential URLs. dakera --check-config prints the warnings before a start; see Operations.

v0.12.0 — The REST port now answers while models download or load, so point readiness probes at /health/ready and liveness probes at /health/live. Every other request answers 503 with Retry-After: 5 until the models are loaded. See Upgrading to v0.12.

Capabilities

MethodPathAuthDescription
GET/v1/capabilitiesRead scopeWhat this server supports, generated from its registries: capabilities_version, server_version, api_versions, default_model, models[] (name, aliases, dimension, max_seq_length, effective_max_seq_length, active, mrl_dimensions, modality), index_kinds, vector_index_kinds, live_vector_index_kinds, distance_metrics, search_mode, search_modes_accepted, fulltext_language, query_languages, on_disk_format_version, records, scoring, attachments, vision, reembed_pending, unreadable_records and late_interaction_stats. From v0.12.2 capabilities_version is 2, with auth (prefix_patterns, sessions_by_agent, key_update, rotation_grace_max_secs, max_grants, max_grant_len), naming (agent id and namespace rules, reserved and internal names) and sessions (idle_timeout_secs, the live value; max_idle_timeout_secs; touch; ended_reason). Clients must ignore unknown fields. From v0.12.3 a documents block says whether document import is on
{
  "capabilities_version": 2, "server_version": "0.12.3", "default_model": "bge-large",
  "models": [ { "name": "bge-m3", "dimension": 1024, "max_seq_length": 8192,
                "effective_max_seq_length": 2048, "active": false, "modality": "text" }, ... ],
  "live_vector_index_kinds": ["hnsw"], "search_mode": "hybrid", "fulltext_language": "en",
  "query_languages": ["en", "de", "fr", "es", "it", "pt", "nl"],
  "records":     { "enabled": false, "representation_kinds": ["dense", "token_multivector", "patch_multivector"],
                   "dtypes": ["f32", "f16", "i8"], "max_representations": 8, "max_vectors": 4096, "max_bytes": 8388608 },
  "scoring":     { "strategy": "single-vector", "late_interaction": { "enabled": false, "model_supported": false, "lane": "text" } },
  "attachments": { "enabled": false, "max_bytes": 26214400, "transcription": { "model": "whisper-tiny.en" } },
  "vision":      { "enabled": false, "model": "colmodernvbert", "media_types": ["image/png"], "dimension": 128 },
  "reembed_pending": false,
  "sessions":    { "idle_timeout_secs": 14400, "max_idle_timeout_secs": 2592000, "touch": true, "ended_reason": true }
}

Authentication

MethodPathAuthDescription
GET/v1/auth/whoamiAny valid keyv0.12.2: the key the request authenticates with, as the server reads it: key_id, name, scope, namespaces, unrestricted, expires_at, grants_version, inert_namespaces (entries that grant nothing) and auth_enabled. Never the key itself

Memory

MethodPathDescription
POST/v1/memory/storeStore a memory
POST/v1/memories/store/batchStore several memories (request-level lang)
POST/v1/memory/recallSemantic recall
POST/v1/memories/recall/batchFilter-based batch recall
GET/v1/memory/get/{id}Get memory by ID. From v0.12.3 agent_id is optional: without it the id is looked up in every agent the key may read (400 naming them when several hold it)
PUT/v1/memory/update/{id}Update memory content, importance, tags or lang
POST/v1/memory/forgetDelete (forget) a memory

Store memory — request body

{
  "agent_id": "my-agent",                  // required
  "content": "User prefers dark mode",       // required
  "importance": 0.8,                         // optional, 0.0–1.0, default 0.5
  "tags": ["preference", "ui"],             // optional
  "session_id": "sess-abc123",              // optional
  "memory_type": "episodic",                 // episodic | semantic | procedural | working
  "lang": "de",                               // optional (v0.12): en, de, fr, es, it, pt, nl; unsupported = 400
  "attachment_ref": "sha256:…",               // optional (v0.12, DAKERA_ATTACHMENTS): an uploaded attachment
  "event_time": "2024-05-07T18:30:00Z"     // optional (v0.12.3): when the event happened, Unix seconds or RFC 3339
}

Other optional fields: id, metadata, ttl_seconds, expires_at. From v0.12.2 every memory write path (store, batch, update, import, transcribe, index) checks: content at most DAKERA_MAX_MEMORY_CONTENT_BYTES UTF-8 bytes (default 100000; on update, a memory already above it may be updated to content no larger than it is now); metadata a JSON object (or null) of at most 100 top-level fields with keys of 1 to 256 bytes; no dakera-curated tag and no _dakera_* metadata key other than _dakera_content_date (integer, unix seconds) and _dakera_lang; no caller id of the form mem_s + 24 hex; ttl_seconds at most 100 years; agent ids at most 241 bytes. When the memory has a session, the store response carries session_state (active or ended; storing into an ended session still succeeds) and the batch response lists ended_sessions. lang selects how event dates, rule-based entity tags and full-text date metadata are parsed and is recorded as _dakera_lang; see Multilingual search.

event_time (v0.12.3), on a store and on each item of a batch store, records when the memory's event happened (Unix seconds or an RFC 3339 timestamp, from 1970 to 2286; otherwise 400 naming the field). Recency, since / until, the time range inferred from a query, the neighbourhood, supersession and the order of events read it instead of the ingest time, so an imported or replayed history reasons about time from its own dates. created_at stays the ingest time (TTL, decay, listings). Request fields the server does not know are still accepted; from v0.12.3 store, batch store, recall and batch recall name them in a warnings array and an X-Dakera-Ignored-Fields header.

Recall — request body

{
  "agent_id": "my-agent",                  // required
  "query": "UI preferences",                // required
  "top_k": 10,                               // optional, default 10, at most 10000
  "lang": "fr",                               // optional (v0.12): language of the query, for routing and dates
  "rerank": true,                             // optional, default true: cross-encoder rerank
  "rerank_candidates": 20,                    // optional (v0.12): score at most 20 candidates with the cross-encoder
  "min_importance": 0.5,                    // optional filter
  "tags": ["preference"],                    // optional filter
  "session_id": "sess-abc123",              // optional: scope to session
  "neighborhood_mode": "separate",         // optional (v0.12.3): inline (default) | separate | off
  "include_summaries": true                // optional (v0.12.3): may session summaries be recalled
}

The recall response carries memories[] (each with score, weighted_score, smart_score), query_embedding_time_ms, search_time_ms, rerank_report and, under late interaction, late_interaction_first_stage. rerank_report is {"applied": true, "candidates": 15}, or {"applied": false, "candidates": 0, "skipped": "…"} with skipped one of disabled, bm25_routing, visual_lane, no_candidates, no_query, unavailable, failed or low_confidence. rerank_candidates is capped by the server-wide DAKERA_RERANK_MAX_CANDIDATES; from v0.12.3, unset means the pool a top_k 10 recall builds (195 pairs with the default settings, 0 = no cap), rerank_report.capped is true when the cap applied, and rerank_candidates: 0 is a 400. A recall no longer raises the importance of the memories it returns, so smart_score values changed scale from v0.11; see Upgrading. At most two recalls per CPU core (at least four) run at once; the rest queue and, from v0.12.3, answer 429 with Retry-After after DAKERA_ADMISSION_WAIT_SECS (default 20 s; 503 before v0.12.3). Recall and search for an agent that has stored nothing answer 200 with no memories. Details: Search and ranking.

Ranking and session context (v0.12.3)

Each result carries rank_score, the score the results are ordered by: it never rises down memories, so sort or threshold on it. score keeps its meaning (the reranker's or retrieval score) and can rise down the list. The first k results of a recall with top_k = k are the first k of a top_k = 10 recall for every k up to 10 (DAKERA_RECALL_RANK_DEPTH), so asking for more results never reorders the head.

neighborhood_mode decides where the neighbouring memories of the top results' sessions go: inline (the default, as before: after the top_k ranked results, each marked retrieval: "neighborhood"), separate (in context_memories, each entry with context_of, the ranked memory it belongs to, so memories holds at most top_k) or off. neighborhood: false still means off. The server default is DAKERA_NEIGHBORHOOD_MODE. A document chunk's neighbours are the chunks before and after it. With DAKERA_RECALL_COLLAPSE_DERIVED=1 a sentence sub-memory and its source share one result, returned as the source with matched_text and matched_ids.

Document import v0.12.3

PDF, DOCX, HTML, Markdown and plain text become chunk memories of an agent that recall can cite. Chunking follows the document's structure (sections at headings, then paragraphs, sentences and words; code blocks and table rows kept whole while they fit), stays within the embedding model's token budget with an overlap, and every chunk carries _dakera_document metadata: document id, title, page range, heading path, chunk index and count. Re-importing a document id keeps unchanged chunks; an import that fails leaves the earlier version as it was. PDF and DOCX are parsed in a sandboxed child process. On by default (DAKERA_DOCUMENTS); GET /v1/capabilities reports documents.

MethodPathDescription
POST/v1/memory/documentsImport text, Markdown or HTML sent as JSON (agent_id, content, media_type, optional title, document_id, chunking and the memory fields of a store). 202 with a job (Write)
POST/v1/namespaces/{ns}/attachments/{ref}/documentImport an uploaded attachment: PDF, DOCX, HTML, Markdown or text. 202 with a job (Write; needs DAKERA_ATTACHMENTS)
GET/v1/memory/documents/jobs/{job_id}?agent_id=Status of an import job
GET/v1/memory/documents?agent_id=List an agent's documents (cursor paging)
GET/v1/memory/documents/{document_id}?agent_id=A document and its chunks (pages, heading path, character range)
DELETE/v1/memory/documents/{document_id}?agent_id=Delete a document with all its chunks
{
  "agent_id": "support-bot",
  "content": "# Install\n\nRun the installer, then …",
  "media_type": "text/markdown",
  "title": "Field manual",
  "chunking": { "max_tokens": 400, "overlap_tokens": 50, "strategy": "structure" }
}

A file that cannot be parsed fails its job with 422 (UNPROCESSABLE_CONTENT), a parse that runs too long with 504 (EXTRACTION_TIMEOUT), and a document over the size or chunk limits with 413. Limits and defaults: Configuration.

Sessions

MethodPathDescription
GET/v1/sessionsList the sessions of the agents the key reaches (a key without grants lists none). With agent_id, every session of the agent, ended or not, newest first (v0.12.0 listed only its open sessions)
POST/v1/sessions/startStart a session (409 if the given id belongs to another agent). Optional idle_timeout_secs (v0.12.2): 0 = never ended for inactivity, at most 2592000; omitted = the server's timeout
GET/v1/sessions/{id}Get session by ID
POST/v1/sessions/{id}/endEnd a session (ended_reason: "client"). Write scope is checked first (a Read key gets 403); an unknown session, or one of an agent the key cannot reach, gets the same idempotent 200 and nothing is written. Ending a session that is already ended returns its stored state. A summary above the content limit is 400
POST/v1/sessions/{id}/touchv0.12.2: record activity on an open session (Write on its agent; otherwise 404). Answers the session, session_state and idle_deadline_at; never re-opens an ended session
GET/v1/sessions/{id}/memoriesGet all memories from a session; opt-in content_preview_chars (v0.12.2, see Agents)
GET/v1/agents/{id}/sessionsList all sessions for an agent

Authorization (v0.12.2). Sessions are authorized by their agent's namespace (_dakera_agent_{agent_id}) alone: a key needs no _dakera_sessions grant (such an entry is accepted and grants nothing).

Idle sessions end by themselves (v0.12.2). A session whose last activity is at least its timeout ago (its own idle_timeout_secs, else DAKERA_SESSION_IDLE_TIMEOUT_SECS, default 14400 = 4 h, 0 = off) is ended by the server exactly as a client end would, with ended_reason: "idle". Activity is a memory stored, batch-stored, imported or updated with the session, a session-scoped recall, search or batch recall, or touch. Sessions carry last_activity_at, ended_reason (client | idle; sessions ended before v0.12.2 read client), idle_since (idle ends) and idle_timeout_secs (when the session set its own).

Batch & advanced memory

MethodPathDescription
POST/v1/memories/recall/batchFilter-based batch recall (no semantic query). A limit above 10000 is cut to it (x-dakera-limit, truncated: true)
DELETE/v1/memories/forget/batchBulk forget by filter predicates
POST/v1/memory/searchSearch with tag and type filters; accepts lang and rerank; answers rerank_report and effective_top_k (a query ranks at most 500 candidates)
POST/v1/memory/importanceBatch-update importance scores
POST/v1/memory/consolidateMerge related memories into summary. Explicit memory_ids that carry an attachment, a TTL or user metadata, or that have expired, are 400
POST/v1/memory/feedbackSubmit feedback on a recalled memory
POST/v1/memories/{id}/feedbackSubmit feedback signal (upvote/downvote/flag)
GET/v1/memories/{id}/feedbackGet feedback history for a memory
PATCH/v1/memories/{id}/importancePatch importance for a single memory

Agents

MethodPathDescription
POST/v1/agentsv0.12.2: create an agent (its memory namespace) before its first memory: {"agent_id": "mlx-dev"}. Needs Write on _dakera_agent_{agent_id}. 201 with created: true, or 200 with created: false for an existing agent, which is not modified; both answer namespace, dimension and model
GET/v1/agentsList all agents: from v0.12.1 every agent with a memory namespace or a session (agents without a session were missing). memory_count is the agent's memories, without sentence sub-memories; vector_count (new) is every stored record of its namespace, the figure memory_count gave up to v0.12.0; session_count counts ended sessions too. From v0.12.2 vector_count no longer counts the namespace seed (an empty agent reports 0), and an entry whose namespace could not be counted carries unavailable
GET/v1/agents/{id}/memoriesList agent memories (at most 1000 per page; the size used is echoed in x-dakera-limit). From v0.12.2 sentence sub-memories are left out unless include_derived=true; opt-in content_preview_chars (1 to 10000, 400 outside) cuts each content to that many characters, never mid-character, and adds content_len and content_truncated. Read a truncated memory in full with GET /v1/memory/get/{id}
GET/v1/agents/{id}/statsAgent statistics: total memories, memories by type, total and active sessions, average importance, oldest and newest memory. From v0.12.1 total_memories excludes sentence sub-memories (new sub_memories) and total_sessions counts ended sessions too (active_sessions stays open-only)
GET/v1/agents/{id}/sessionsList agent sessions
GET/v1/agents/{id}/wake-upStartup context: the top memories by importance × recency of use (top_n default 20, at most 100; optional min_importance), without embedding a query. From v0.12.2 sentence sub-memories are left out unless include_derived=true, and total_available counts memories only
POST/v1/agents/{id}/consolidateConsolidate agent memories
POST/v1/agents/{id}/compressCompress agent memory. From v0.12.2 each summary is validated before it is written; a refused one is listed in summaries_skipped and its cluster's originals are not deprecated
GET/v1/agents/{id}/consolidation/logConsolidation history log
PATCH/v1/agents/{id}/consolidation/configUpdate consolidation config

Feedback

MethodPathDescription
GET/v1/agents/{id}/feedback/summaryAggregated feedback stats for an agent
GET/v1/feedback/healthSystem-wide feedback quality metrics

Vectors

MethodPathDescription
POST/v1/namespaces/{ns}/vectorsUpsert vectors
POST/v1/namespaces/{ns}/queryANN vector similarity search
POST/v1/namespaces/{ns}/vectors/deleteDelete vectors by ID
POST/v1/namespaces/{ns}/vectors/bulk-updateBulk-update metadata by filter
POST/v1/namespaces/{ns}/vectors/bulk-deleteBulk-delete vectors by filter
POST/v1/namespaces/{ns}/vectors/countCount vectors (with optional filter)
POST/v1/namespaces/{ns}/batch-queryBatch vector queries in parallel
POST/v1/namespaces/{ns}/multi-vectorMulti-vector search with MMR diversity
POST/v1/namespaces/{ns}/unified-queryFlexible ranking (vector, text, or attribute)
POST/v1/namespaces/{ns}/aggregateAggregation queries (count, sum, avg, min, max)
POST/v1/namespaces/{ns}/upsert-columnsColumn-format upsert (efficient batch)
POST/v1/namespaces/{ns}/explainQuery execution plan and cost estimate
POST/v1/namespaces/{ns}/warmPre-load vectors into memory cache
POST/v1/namespaces/{ns}/cache/warmWarm namespace cache
POST/v1/namespaces/{ns}/exportExport vectors with pagination

From v0.12.2 the raw vector routes of an agent namespace (vectors, upsert-columns, records, upsert-text and gRPC Upsert) refuse a payload carrying _dakera_type and refuse to replace an existing memory record; vectors/bulk-update refuses an update that sets _dakera_type or selects a memory record (400, pointing at /v1/memory/*). Plain vectors in agent namespaces and every payload in other namespaces are unaffected.

MethodPathDescription
POST/v1/namespaces/{ns}/fulltext/indexIndex documents for BM25 search
POST/v1/namespaces/{ns}/fulltext/searchBM25 full-text search
POST/v1/namespaces/{ns}/fulltext/deleteDelete from full-text index
GET/v1/namespaces/{ns}/fulltext/statsFull-text index statistics
POST/v1/namespaces/{ns}/hybridVector + BM25 hybrid search

Text inference (auto-embedding)

MethodPathDescription
POST/v1/namespaces/{ns}/upsert-textUpsert text with server-side embedding
POST/v1/namespaces/{ns}/query-textQuery by natural language text
POST/v1/namespaces/{ns}/batch-query-textBatch text queries
POST/v1/extractExtract structured info from text
POST/v1/routeSemantic query routing

Attachments & records opt-in, v0.12

Off by default. A server that has not enabled a feature answers its routes 501 FEATURE_DISABLED with the variable that turns it on. Attachments need DAKERA_ATTACHMENTS, image indexing also DAKERA_VISION, and records DAKERA_RECORDS. See Multimodal memory and Records and multi-vector.

MethodPathScopeDescription
POST/v1/namespaces/{ns}/attachmentswriteUpload (multipart file field, or a raw body with its Content-Type). 201 with attachment_ref (sha256:<hex>), content_type, size_bytes, created; 200 when the namespace already held the bytes; 413 over DAKERA_ATTACHMENT_MAX_BYTES (default 25 MiB)
GET/v1/namespaces/{ns}/attachmentsreadList attachments ({"attachments": [...]}, no bytes)
GET/v1/namespaces/{ns}/attachments/{ref}readThe bytes, with the uploaded media type and an ETag
DELETE/v1/namespaces/{ns}/attachments/{ref}write204; 409 while a memory references it
POST/v1/namespaces/{ns}/attachments/{ref}/transcriberead on {ns} + write on the agentSpeech to text (DAKERA_WHISPER_MODEL, default whisper-base; WAV only): 202 with job_id, memory_id, model and status_url. Body: agent_id (required) plus the memory fields
GET/v1/namespaces/{ns}/attachments/{ref}/transcribe/{job_id}readJob status (progress, message, error on failure)
POST/v1/namespaces/{ns}/attachments/{ref}/indexread on {ns} + write on the agentImage indexing for visual recall (colmodernvbert, PNG only). Same request and answer as transcribe, plus an optional content caption
GET/v1/namespaces/{ns}/attachments/{ref}/index/{job_id}readJob status
POST/v1/namespaces/{ns}/recordswriteUpsert records: {"records": [{"id", "values", "representations": [{"name", "kind", "vectors", "store_as"}], "metadata"}]} answers {"upserted_count": n}
GET/v1/namespaces/{ns}/records/{id}readRead a record: dimension and a manifest of its representations (include_vectors=true adds the vectors)

A memory references an attachment with attachment_ref on POST /v1/memory/store; the attachment must have been uploaded to the memory's own namespace _dakera_agent_{agent_id} (otherwise 404). The transcription and image jobs read an attachment from any namespace the key can read and copy it into the agent's. Representation kind is dense, token_multivector or patch_multivector; store_as is f32 (default, lossless), f16 or i8; one record holds at most 8 extra representations, DAKERA_RECORD_MAX_VECTORS (default 4096) vectors per representation and DAKERA_RECORD_MAX_BYTES (default 8 MiB) in all, and over a limit is 413. A record upsert replaces the whole record; there is no record delete route, delete the id through the vector routes.

Jobs return 202 and are polled: status is Pending, Running, Completed or Failed, a failed job carries error: {status, code}, and job ids (job_<run>_<n>) are unknown after a restart (404 JOB_NOT_FOUND; the stored memory is kept, find it by memory_id). Every media job reserves its estimated peak memory first; if it does not fit within 10 s the answer is 503 with Retry-After.

Namespaces

MethodPathDescription
GET/v1/namespacesList all namespaces; from v0.12.2 with a kinds map (agent or data)
POST/v1/namespacesCreate a namespace
GET/v1/namespaces/{ns}Get namespace details (v0.12.2: kind). Agent namespaces _dakera_agent_{id} accept dots, up to 255 bytes; other names stay at 128 bytes without dots. _dakera_embedding_models is reserved
PUT/v1/namespaces/{ns}Create or configure a namespace (dimension required, distance optional; an existing namespace keeps its other configuration)
DELETE/v1/namespaces/{ns}Delete a namespace
GET/v1/namespaces/{ns}/configGet entity extraction config
PUT/v1/namespaces/{ns}/configReplace entity extraction config (extract_entities required; an omitted entity_types clears the list)
PATCH/v1/namespaces/{ns}/configMerge an entity extraction change (only the fields sent change); an unknown field is 400
GET/v1/namespaces/{ns}/extractorGet extraction provider config
PATCH/v1/namespaces/{ns}/extractorSet extraction provider
GET/v1/namespaces/{ns}/memory_policyGet lifecycle policy
PUT/v1/namespaces/{ns}/memory_policyReplace the lifecycle policy (omitted fields take their defaults). Unknown fields, a changed consolidated_count and rate_limit_enabled without a cap are 400; the policy is re-applied at startup

Namespace API keys

MethodPathDescription
POST/v1/namespaces/{ns}/keysCreate a namespace-scoped API key; extra_namespaces accepts prefix patterns (v0.12.2) contained in the caller's grants
PATCH/v1/namespaces/{ns}/keys/{key_id}v0.12.2: rename a key or replace its namespaces, for a namespace admin. Every new grant must be contained in the caller's (403 otherwise); a key the caller cannot manage answers 404
GET/v1/namespaces/{ns}/keysList keys for a namespace
DELETE/v1/namespaces/{ns}/keys/{key_id}Revoke a namespace key
GET/v1/namespaces/{ns}/keys/{key_id}/usageKey usage statistics

Knowledge graph

MethodPathDescription
GET/v1/memories/{id}/graphBFS traversal from a memory
GET/v1/memories/{id}/pathShortest path between two memories
POST/v1/memories/{id}/linksCreate explicit link between memories
GET/v1/agents/{id}/graph/exportExport agent knowledge graph
GET/v1/knowledge/queryQuery KG with filter DSL
GET/v1/knowledge/pathFind paths in KG
GET/v1/knowledge/exportExport KG as JSON/GraphML

Knowledge operations

MethodPathDescription
POST/v1/knowledge/graphBuild knowledge graph from seed memory
POST/v1/knowledge/summarizeSummarize a set of memories
POST/v1/knowledge/deduplicateFind and merge duplicates (dry_run to only report); 400 past 5000 memories to compare, narrow with memory_type. From v0.12.2 the merged tags are capped at 50 and duplicates_skipped_changed counts duplicates not merged because a record changed meanwhile
POST/v1/knowledge/graph/fullFull knowledge graph with related memories. Opt-in content_preview_chars (v0.12.2, 1 to 10000) cuts each node's content; every node carries content_len and content_truncated. Sentence sub-memories are never nodes
POST/v1/knowledge/network/cross-agentCross-agent memory network (same content_preview_chars option)
GET/v1/memory/deduplicated?agent_id=v0.12.3: memories removed by deduplication or consolidation that can still be restored (id, kind, survivor_id, session_id, deleted_at, restorable_until) (Read)
POST/v1/memory/deduplicated/{id}/restore?agent_id=v0.12.3: put one back under its own id, dates and session (Write); 404 without a restorable copy, 409 when the agent holds that id again

From v0.12.3 deduplication (POST /v1/knowledge/deduplicate without dry_run, and AutoPilot in merge mode) and consolidation delete softly: each removed memory stays restorable for DAKERA_AUTOPILOT_TRASH_RETENTION_HOURS (default 168, 0 = no copy) and every removal is an audit event (deduplicated or consolidated; a restore is restored). AutoPilot deduplication is off by default (DAKERA_AUTOPILOT_DEDUP_MODE: off, report or merge).

Entity extraction

MethodPathDescription
POST/v1/memories/extractExtract entities from text
GET/v1/memory/entities/{id}Get entities for a memory

Import & export

MethodPathDescription
GET/v1/exportExport an agent's memories (agent_id; format jsonl (default), csv, mem0 or zep)
POST/v1/importImport memories for an agent (multipart upload; format explicit or detected). From v0.12.2 each item is validated as a new memory; refused items are skipped with their reason in the job's errors, and an attachment_ref must resolve
GET/v1/import/{job_id}/statusCheck import job status

Audit & events

MethodPathDescription
GET/v1/auditQuery audit log
GET/v1/audit/streamStream audit events (SSE)
GET/v1/audit/exportExport audit log
GET/v1/events/streamStream memory lifecycle events (SSE)
GET/v1/namespaces/{ns}/eventsStream namespace events (SSE)

From v0.12.2 open streams re-check their key every 15 s: a stream closes when the key is deleted, deactivated or expired, or no longer has the scope and namespaces the stream needs. session_ended events carry reason (client | idle).

Analytics & operations

MethodPathDescription
GET/v1/analytics/overviewHigh-level metrics (QPS, latency, storage). cache_hit_rate and cache_lookups (the count it comes from; 0 means no data) include the in-process cache from v0.12.1 (v0.12.0: the Redis tier only). The query latency covers recalls and searches only. New in v0.12.1: total_memories, internal_vectors
GET/v1/analytics/latencyLatency percentiles and trends
GET/v1/analytics/throughputRequest throughput by operation
GET/v1/analytics/storageStorage breakdown by namespace
GET/v1/ops/statsOperational stats. New in v0.12.1: total_memories, internal_vectors, internal_namespaces, agent_namespaces
GET/v1/ops/metricsOps metrics
GET/v1/kpisProduct KPI snapshot. From v0.12.1 batch recall, batch store and memory search are counted, session_count_weekly is the sessions started in the last 7 days (v0.12.0: open sessions), and a latency object (window_seconds, recall_samples, store_samples, recalls_total, stores_total) tells an idle window from a missing measurement
Statistics totals (v0.12.1). Every count endpoint uses one definition: a memory is a top-level memory an agent stored, a sub-memory is a sentence record derived from one for keyword search, and a vector is any stored record. Field names and types are unchanged; after the upgrade memory counts drop and session counts rise. See Statistics totals.

Operations (/ops)

All need a global admin key (no namespace restriction).

MethodPathDescription
GET/ops/diagnosticsProcess, resource, component and storage-integrity snapshot
GET/ops/jobsBackground jobs held in memory (compaction, dimension migration, transcription, image indexing); finished jobs are evicted after an hour
GET/ops/jobs/{id}One job; 404 JOB_NOT_FOUND for an unknown id (ids carry the run: job_<run>_<n>)
POST/ops/compactRun the storage backend's compaction now and answer what it did; 501 on a backend without on-request compaction (only the segmented backend has it)
POST/ops/shutdownStart the graceful shutdown (it really stops the server since v0.12; v0.11 answered and kept running). From v0.12.3 it needs a global super_admin key
GET/ops/eventsGlobal event stream (SSE)
GET/debug/configNon-secret DAKERA_* variables active in the process
v0.11.91 — Versioned admin paths — All /admin/* endpoints listed below are also served at /v1/admin/* (e.g. /v1/admin/autopilot/status). The versioned path is what the official SDKs use. Exception: /admin/keys/* remains at the unversioned path only.

Admin — cluster

MethodPathDescription
GET/admin/cluster/statusCluster state, node and vector counts, Redis health and, in cluster mode, election (term, leader, lease, quorum) and replication (outbox_entries, outbox_durable, versioning_active, tombstones, startup_reconciled, reconcile_source)
GET/admin/cluster/nodesAll nodes with state and roles
GET/admin/cluster/replicationReplication status
GET/admin/cluster/shardsOne entry per namespace on this node. There is no sharding: every node holds all the data
POST/admin/cluster/shards/rebalanceKept for compatibility; with no sharding it moves nothing (planned_moves is empty)
GET/admin/cluster/maintenanceMaintenance mode status
POST/admin/cluster/maintenance/enableEnter maintenance mode on the receiving node (not replicated, not persisted; reject_requests answers 503 with Retry-After outside admin, ops, health and metrics routes)
POST/admin/cluster/maintenance/disableExit maintenance mode (409 while maintenance jobs run, unless force)

Admin — API keys

MethodPathDescription
POST/admin/keysCreate a global API key. namespaces: null or ["*"] = every namespace, [] = none, exact names, or prefix patterns p* (v0.12.2); invalid entries are 400
GET/admin/keysList all API keys
GET/admin/keys/{id}Get key details
PATCH/admin/keys/{id}v0.12.2: rename a key or replace its namespaces ({"name", "namespaces"}; scope cannot change). Root key 400, inactive key 409
DELETE/admin/keys/{id}Delete a key
POST/admin/keys/{id}/deactivateDeactivate a key
POST/admin/keys/{id}/rotateRotate a key. Optional {"grace_secs": N} (v0.12.2, up to 604800): the old key keeps working until min(its expiry, now + N); the response adds old_key_id and old_key_expires_at. key_id is the new key's id. An empty body behaves as before
GET/admin/keys/{id}/usageKey usage statistics

Admin — storage & indexes

MethodPathDescription
GET/admin/indexes/statsLive index per namespace (flat or hnsw), size and vectors covered
POST/admin/indexes/rebuildRebuild ANN indexes from storage and report what each namespace did (an index type that differs from the engine's choice is 400)
GET/admin/cache/statsCache performance stats (from v0.12.1 including the in-process cache, not only Redis)
POST/admin/cache/clearClear cache
POST/admin/cache/warmWarm cache
POST/admin/fulltext/reindexBackfill the full-text index, or with rebuild (implied when the analyzer changed) rebuild it under the current DAKERA_FULLTEXT_LANGUAGE / CJK bigram settings; answers per-namespace rebuilt and analyzer_language
POST/admin/reembed/drainSynchronous quality drain for DAKERA_TIERED=1: re-embed pending static-tier memories. timeout_secs defaults to 600 and is capped at 4/5 of DAKERA_REQUEST_TIMEOUT (timed_out in the answer); a second drain is 409
GET/admin/reembed/static-countCount of static-tier memories pending ONNX upgrade
GET/admin/reembed/migrationProgress of the one-time document-side re-embed of stored memories after the upgrade (state, remaining, rate_per_sec, eta_secs, per-namespace counts)
GET/admin/derivations/statusv0.12.2: what derived data is owed across agent namespaces (pending, stale, orphan and duplicate sentence sub-memories, missing full-text entries, owed graph edges), settled, the reconciler's state and this node's one-time heal
POST/admin/derivations/drainv0.12.2: run the heal and every agent namespace's reconciliation now, on this node, until nothing is owed or timeout_secs (default 600, capped at 4/5 of DAKERA_REQUEST_TIMEOUT); answers settled and timed_out
GET/admin/storage/tiersStorage tier overview
POST/admin/ttl/cleanupManual TTL cleanup
GET/admin/ttl/statsTTL statistics; from v0.12.1 expired_pending_cleanup is reported (it was always 0)

Admin — AutoPilot, decay & config

MethodPathDescription
GET/admin/autopilot/statusAutoPilot status and last-run stats
PUT/admin/autopilot/configUpdate AutoPilot config
POST/admin/autopilot/triggerTrigger AutoPilot cycle
GET/admin/decay/configGet decay config
PUT/admin/decay/configUpdate decay config
GET/admin/decay/statsDecay statistics
GET/admin/configGet the effective server config (the six live settings are read back from what enforces them)
PUT/admin/configUpdate server config. max_vectors_per_namespace, cache_enabled, cache_max_size_bytes, rate_limit_enabled, rate_limit_rps query_timeout_ms (504 QUERY_TIMEOUT; 0 = none) and, from v0.12.2, session_idle_timeout_secs (0 to 2592000) take effect at runtime and are listed in runtime_overrides; any bad value among them is 400 and nothing is applied

Admin — quotas

MethodPathDescription
GET/admin/quotasList all quotas
GET/admin/quotas/defaultGet default quota
PUT/admin/quotas/defaultSet default quota
GET/admin/quotas/{ns}Get namespace quota
PUT/admin/quotas/{ns}Set namespace quota
DELETE/admin/quotas/{ns}Delete namespace quota
POST/admin/quotas/{ns}/checkCheck whether an operation would exceed the namespace quota, without writing
Quotas are enforced in v0.12. v0.11 stored quotas but no write consulted them. With the default hard enforcement, a write that would take a namespace over max_vectors, max_storage_bytes, max_dimensions or max_metadata_bytes is refused with 413 (QUOTA_EXCEEDED) on every write path (REST, gRPC, memory, import, re-embed). soft logs a warning and writes; none only tracks.

Admin — backup & recovery

MethodPathDescription
GET/admin/backupsList backups
POST/admin/backupsCreate a backup: 202 and poll GET /admin/backups/{id}. encrypt (AES-256-GCM per file, key derived from DAKERA_ENCRYPTION_KEY) and compression (zstd or none) are applied; lz4, or encrypt without a key, is 400. Backups carry attachments and graph edges
GET/admin/backups/{id}Get backup details
DELETE/admin/backups/{id}Delete a backup
GET/admin/backups/{id}/downloadDownload backup file (global super_admin in v0.12)
POST/admin/backups/uploadUpload backup for restore (global super_admin in v0.12)
POST/admin/backups/restoreRestore from backup (global super_admin in v0.12). Without overwrite the backup's records are written over current copies and later records are kept; with "overwrite": true the result is the backup's point in time. One restore at a time (409); status is inprogress, completed or failed
GET/admin/backups/restore/{id}Get restore status
GET/admin/backups/scheduleGet backup schedule
POST/admin/backups/scheduleUpdate backup schedule. A stored, enabled schedule now runs (v0.11 never ran it); an invalid cron expression or an encrypt / compression a backup cannot honor is 400
Permissions in v0.12. A key pinned to namespaces no longer reaches node-wide routes: /admin/*, /ops/*, /v1/analytics/*, /v1/kpis, /v1/events/stream and the audit routes answer 403 unless the key has the required scope with no namespace restriction. Backup download, upload and restore need global super_admin. /admin/keys/* still needs super_admin. GET /v1/export and POST /v1/import now need read / write on the agent's namespace. Four admin routes stay namespace-scoped (a pinned admin key may call them for its own namespaces): DELETE /admin/namespaces/{ns}, POST /admin/namespaces/{ns}/optimize, POST /admin/cache/warm and POST /admin/indexes/rebuild. Details in Upgrading to v0.12.
Node-wide endpoints (v0.12.2) — /v1/ops/stats, /admin/indexes/stats, /admin/namespaces, /admin/memory-type-stats, /admin/ttl/stats, /admin/cluster/status, /admin/cluster/nodes, /admin/cluster/shards, /admin/storage/tiers, /v1/analytics/overview and /v1/analytics/storage work on each namespace concurrently under a 2 s deadline. A namespace that fails or does not answer is left out of the totals and listed in unavailable: [{namespace, reason}] (absent when every namespace answered).

Admin — namespaces

MethodPathDescription
GET/admin/namespacesList all namespaces (admin view with full metadata); from v0.12.2 each entry has a kind (agent, data or system)
POST/admin/namespaces/migrate-dimensionsRe-embed agent namespaces with the active model and migrate their dimension; reembed_same_dimension: true completes an embedding-model change at the same dimension (for example bge-large to bge-m3); runs as a job (job_id). From v0.12.1 a model change re-embeds the store in the background by itself; this call is for the cases that background change cannot handle (DAKERA_TIERED=1, late-interaction scoring, the visual lane, a recorded model this build does not know), after a start with DAKERA_ALLOW_MODEL_CHANGE=1
DELETE/admin/namespaces/{namespace}Delete a namespace and all its data
POST/admin/namespaces/{namespace}/optimizeCompact the namespace (segmented backend) and rebuild its ANN index, on this node, and answer what each step did

Admin — monitoring

MethodPathDescription
GET/admin/slow-queriesList slow queries
GET/admin/slow-queries/summarySlow query summary
DELETE/admin/slow-queriesClear slow query log
POST/admin/encryption/rotate-keyRotate the data key of one namespace or of every namespace; new_key is optional (random when omitted), wait_secs (default 10, max 300) bounds the wait for the background re-seal. DAKERA_ENCRYPTION_KEY does not change
GET/admin/encryption/statusKeyring (key ids, which key seals which namespace; never key material), re-seal progress and every node's last complete pass
POST/admin/encryption/resealRun a re-seal pass now (202 while it runs)
POST/admin/encryption/keys/{key_id}/revoke-masterRevoke the master of a retired operator key (409 while it still seals values)
GET/admin/background-activityBackground task status
GET/admin/memory-type-statsMemory type distribution. From v0.12.1 total counts memories (sentence sub-memories in the new sub_memories; new agent_namespaces)
PATCH/admin/slow-queries/configUpdate the slow query threshold at runtime
GET/admin/vectors/{ns}/exportExport a namespace's vectors as JSON Lines
POST/admin/vectors/{ns}/importBulk-import vectors (JSON, JSONL or CSV)
GET/admin/vectors/{ns}/{id}/versionsVersion-history summary of a vector (needs DAKERA_VECTOR_VERSIONING=true)
GET/admin/vectors/{ns}/{id}/versions/{version}One historical version of a vector
Language SDKs — The REST API is the complete interface. The Python, TypeScript, Go and Rust SDKs wrap it with typed requests and retries. The MCP server exposes Dakera to MCP clients such as Claude and Cursor: 14 core tools by default, more through its profiles.

Errors

Since v0.12 every error body is JSON with the same shape, including refusals made before a handler runs:

{ "error": "Namespace not found: unknown", "code": "NAMESPACE_NOT_FOUND", "status": 404,
  "details": "namespace: unknown", "resource": "namespace" }

details is optional; resource appears on 404 bodies. Error text never carries backend text such as object-store keys or file paths. The authentication layer's 401 keeps its v0.11 fields (error: "authentication_error", message) and adds code and status.

CodeHTTPMeaning
INVALID_REQUEST400 (422 wrong body shape)Invalid body or parameters; the message names the rule applied (an unsupported lang, a client-supplied sealed value, a reserved metadata key, ...)
EMPTY_VECTOR / DIMENSION_MISMATCH400Empty vector, or a dimension that differs from the namespace's
AUTHENTICATION_REQUIRED / INVALID_API_KEY / API_KEY_EXPIRED401No key, an invalid key, an expired key
INSUFFICIENT_SCOPE / NAMESPACE_ACCESS_DENIED403The key lacks the scope, is pinned to other namespaces, or is pinned and the route spans the whole deployment (details: namespace: *)
CROSS_ORIGIN_REQUEST_REFUSED403With authentication off, a state-changing request from a web page of another origin
HOST_NOT_ALLOWED421v0.12.3, authentication off: the Host is a dotted name not listed in DAKERA_ALLOWED_HOSTS
NAMESPACE_NOT_FOUND404Unknown namespace (resource: namespace)
VECTOR_NOT_FOUND404A vector, memory, session, attachment, graph path or import job was not found; resource says which (the v0.11 code is kept)
API_KEY_NOT_FOUND / JOB_NOT_FOUND404Unknown API key; unknown /ops or media job id (for example from before a restart)
ROUTE_NOT_FOUND / METHOD_NOT_ALLOWED / UNSUPPORTED_MEDIA_TYPE404 / 405 / 415Refusals made before a handler runs; Allow lists the methods of a 405
REQUEST_TIMEOUT408The request ran past DAKERA_REQUEST_TIMEOUT (default 300 s)
CONFLICT409A restore or drain already running, a session id owned by another agent, an attachment still referenced, maintenance/disable while jobs run, a backup whose files are on another node
PAYLOAD_TOO_LARGE413The request is over a limit: DAKERA_MAX_BODY_SIZE, DAKERA_ATTACHMENT_MAX_BYTES, a record limit; the message names the limit
QUOTA_EXCEEDED413The namespace is full: a write would pass a hard quota
UNPROCESSABLE_CONTENT422v0.12.3: a document that cannot be parsed. Also from v0.12.3, POST /admin/keys, POST /v1/namespaces/{ns}/keys, POST /admin/backups and POST /admin/encryption/rotate-key answer 422 to a field they do not know
RATE_LIMIT_EXCEEDED429Server-wide or per-namespace rate limit; carries X-RateLimit-* and Retry-After. From v0.12.3 also an overloaded server: a store, batch store or recall that waited DAKERA_ADMISSION_WAIT_SECS for capacity (Retry-After: 5, details naming the queue)
STORAGE_ERROR / INTERNAL_ERROR500Storage or internal failure; the message never carries backend text
NOT_IMPLEMENTED501A configuration the server cannot honor (late interaction on a model without a recipe or with DAKERA_TIERED=1, an invalid DAKERA_EXTRACTOR_*, compaction on a backend without it); details name the settings
FEATURE_DISABLED501An opt-in feature that is off; details say which variable enables it
SERVICE_UNAVAILABLE503Transient: a model loading or not loadable, a full queue, memory admission, maintenance mode, the server starting. Always carries Retry-After
QUERY_TIMEOUT504A query, recall or search ran past query_timeout_ms; EXTRACTION_TIMEOUT (v0.12.3): a document parse ran past DAKERA_DOCUMENT_EXTRACT_TIMEOUT_SECS

Retry-After. Every 503 carries Retry-After in seconds (never 0): the server's own estimate where it has one (5 s while starting, the memory budget's wait for media jobs, 30 s for a refused image-indexing page, the time to the scheduled end, else 60 s, in maintenance mode), else 5 s. A 429 carries the time to the window's reset. 408, 413, 501 and 504 carry none.

New to Dakera? Start with the Quickstart. For how retrieval, decay and the knowledge graph fit together, see How memory works.

REST API or SDK

Every SDK and the MCP server call the routes on this page. Use an SDK for typed requests and retries, or connect an MCP client to give a model direct access to memory.

Python SDK → MCP Server →
Stay sharp on agent memory
Benchmark results, SDK releases, and production patterns. Under 500 words per issue.
✓ You're in. First issue lands soon — watch for Dakera in your inbox.