Skip to content

API Reference

Base URL: https://core.mnemoverse.com/api/v1

All /memory/* endpoints require authentication via X-Api-Key header or Authorization: Bearer header. Health endpoints (/health, /health/ready) are public and unauthenticated. Internal administrative endpoints exist but use separate authentication and are not part of the public API.

Authentication

Include your API key in every request:

bash
# Option 1: X-Api-Key header (recommended)
curl -H "X-Api-Key: mk_live_YOUR_KEY" ...

# Option 2: Bearer token
curl -H "Authorization: Bearer mk_live_YOUR_KEY" ...

Endpoints

POST /memory/write

Store a single memory atom.

Request:

FieldTypeRequiredDescription
contentstringYesThe insight, pattern, or lesson to remember (1-10,000 chars)
conceptsstring[]NoKey concepts for Hebbian associations
domainstringNoNamespace: general, user:X, project:Z (default: general)
metadataobjectNoArbitrary key-value metadata
external_refstringNoClient-provided unique reference for idempotent writes

Response:

FieldTypeDescription
storedbooleanTrue if the atom passed the importance gate
atom_idUUIDUUID of the stored atom, or null if filtered
importancefloatComputed importance score [0, 1]
reasonstringWhy stored or filtered

POST /memory/write-batch

Store up to 500 atoms in one request.

Request:

FieldTypeRequiredDescription
itemsWriteRequest[]YesArray of write requests (1-500)

Response:

FieldTypeDescription
total_countintTotal atoms processed
stored_countintAtoms that passed importance gate
resultsobject[]Per-atom results with index, stored, atom_id, importance, error

POST /memory/read

Query memory with semantic search + Hebbian expansion.

Request:

FieldTypeRequiredDescription
querystringYesNatural language query (1-5,000 chars)
top_kintNoMax results (1-100, default: 10)
domainstringNoFilter by domain (null = all)
min_relevancefloatNoMinimum relevance threshold (0-1, default: 0.3)
include_associationsboolNoExpand via Hebbian associations (default: true)
conceptsstring[]NoConcept hints to bias search

Response:

FieldTypeDescription
itemsMemoryItem[]Matching memories, ordered by relevance
episodic_hitbooleanTrue if exact fingerprint match found
query_conceptsstring[]Concepts extracted from query
expanded_conceptsstring[]Concepts after Hebbian expansion
search_time_msfloatSearch duration in milliseconds

MemoryItem fields:

FieldTypeDescription
atom_idUUIDUnique identifier
contentstringStored text content
relevancefloatFinal score (similarity * valence modulation)
similarityfloatRaw cosine similarity
valencefloatOutcome polarity [-1, +1]
importancefloatImportance score [0, 1]
sourcestringHit source: episodic, semantic, or hebbian
conceptsstring[]Associated concepts
domainstringDomain namespace
metadataobjectArbitrary metadata

POST /memory/read-batch

Batch query up to 50 queries in one request.

Request:

FieldTypeRequiredDescription
queriesReadRequest[]YesArray of read requests (1-50)

Response:

FieldTypeDescription
resultsReadResponse[]Per-query results

POST /memory/query

Advanced query with multi-domain and metadata filtering.

Request:

FieldTypeRequiredDescription
querystringYesNatural language query
domainsstring[]NoFilter by multiple domains
metadata_filterFilter[]NoJSONB metadata conditions (eq, contains, in)
top_kintNoMax results (default: 10)
min_relevancefloatNoMin relevance (default: 0.3)
include_associationsboolNoHebbian expansion (default: true)
conceptsstring[]NoConcept hints

POST /memory/feedback

Report outcome (success/failure) for memories. Updates valence and Hebbian associations.

Request:

FieldTypeRequiredDescription
atom_idsUUID[]YesAtoms to update
outcomefloatYesOutcome signal: -1.0 (failure) to +1.0 (success)
conceptsstring[]NoConcepts to reinforce
query_conceptsstring[]NoOriginal query concepts (enables co-activation learning)
domainstringNoDomain for the feedback

Response:

FieldTypeDescription
updated_countintNumber of atoms updated
avg_valencefloatAverage valence after update
coactivation_edgesintHebbian edges created/updated

POST /memory/consolidate

Trigger sleep consolidation. Clusters similar memories into prototypes, protects distinctive ones as singletons.

Request:

FieldTypeRequiredDescription
domainstringNoDomain to consolidate (null = general)

Response:

FieldTypeDescription
domainstringDomain consolidated
atoms_beforeintAtom count before
atoms_afterintAtom count after
prototypes_createdintNew prototype atoms
singletons_protectedintVon Restorff protected atoms
compression_ratiofloatatoms_before / atoms_after
duration_msfloatDuration in milliseconds

GET /memory/stats

Get memory statistics for your tenant.

Response:

FieldTypeDescription
total_atomsintTotal atoms stored
episodesintEpisode-type atoms
prototypesintPrototype atoms (from consolidation)
singletonsintProtected singleton atoms
hebbian_edgesintConcept-concept association edges
episodic_fingerprintsintNumber of distinct episodic-content fingerprints across stored atoms
domainsstring[]Active domain names
avg_valencefloatAverage outcome valence
avg_importancefloatAverage importance score

GET /memory/atoms/

Fetch a single atom by ID. Returns the full atom envelope (content, concepts, importance, valence, domain, created_at, etc.). Returns 404 NOT_FOUND if the atom does not exist in your tenant.


DELETE /memory/atoms/

Permanently delete one atom. Idempotent: deleting an already-gone atom returns 200 with {"deleted": 0, "atom_id": "..."} rather than 404 — so retry loops are safe.


DELETE /memory/domain/

Wipe every atom in a domain (e.g. project:old-client). Returns the count of deleted atoms in {"deleted": <int>, "domain": "..."}. Note: the REST route itself currently has no confirm-style interlock — the safety gate (confirm: true) lives in the MCP memory_delete_domain tool schema, not the HTTP layer. Treat this endpoint as destructive on the client side.


DELETE /memory/reset

⚠️ Destructive — wipes ALL atoms in your tenant across every domain. Disabled by default: gated server-side and returns 403 FORBIDDEN unless explicitly enabled on the deployment. Intended for benchmark / staging tenants only; production deployments keep it disabled. Returns total deleted count.


GET /memory/domains

List active domain names in your tenant. Same data as the domains field of /memory/stats, but cheaper if you only need the list.


POST /memory/atoms/by-external-ref

Look up a single atom by its external_ref (the optional client-supplied identifier set during write). Useful when the client wants to recover an atom ID after restart. Request body: { "external_ref": "<string, 1-255 chars>" }. Response: a single atom envelope (same shape as GET /memory/atoms/{atom_id}). Returns 404 NOT_FOUND if no atom matches.


GET /memory/export

Stream every atom in the calling tenant as JSONL (one atom JSON per line). Always tenant-scoped — there is no cross-tenant export and no domain filter; if you need a specific domain, post-filter the stream client-side. For backup / migration.


Health Endpoints

Two monitoring probes for load balancers, uptime services, and post-deploy smokes. Both are public — no authentication required — and are the only non-authed routes under /api/v1/. Hit them as often as your monitoring allows; cost is a single DB SELECT 1 on /health/ready, nothing on /health.

GET /health

Liveness probe. Returns 200 as long as the process is serving. Does NOT check the database, embedding model, or any downstream — a 200 here only means "uvicorn is accepting connections".

Response:

FieldTypeDescription
statusstringAlways "ok" when the process is up.
databasebooleanAlways false — this endpoint intentionally skips the DB round-trip. Use /health/ready for DB status.
versionstringService version (matches the deployed container).

Example:

bash
curl https://core.mnemoverse.com/api/v1/health
# {"status":"ok","database":false,"version":"1.0.0"}

When to use: load-balancer liveness probes, uptime monitors that only care "is the process alive?". Safe at high frequency.


GET /health/ready

Readiness probe. Verifies the service can actually handle traffic — database reachable, memory engine initialised, embedding backend ready. This is what the post-deploy smoke hits to confirm a Railway deploy rolled out successfully.

Response:

FieldTypeDescription
readybooleantrue only when every sub-check passes.
checks.databasebooleanDB pool is connected and SELECT 1 succeeds.
checks.enginebooleanMemoryEngine initialised and wired to storage.
checks.embeddingbooleanLocal model loaded OR API backend responded to warm-up.
versionstringService version.

Example:

bash
curl https://core.mnemoverse.com/api/v1/health/ready
# {"ready":true,"checks":{"database":true,"engine":true,"embedding":true},"version":"1.0.0"}

When to use:

  • Kubernetes / Railway readiness probe — route traffic only after this returns 200 with every sub-check true.
  • Post-deploy smoke tests. Reference retry shape: poll up to 8 × 15 s (2 min cap, enough for a typical Railway rollout), assert HTTP 200 AND ready === true AND every checks.* field is true. Any false = deploy regression; fail the smoke.
  • Your own monitoring: alert when ready=false persists for longer than a deploy window (~2 min).

Status code: always 200 while the process is up. Sub-check values live in the body — ready=false is still a 200 response. This keeps the health surface distinct from errors the retry-wrapping proxies would otherwise treat as transient.


Error Responses

All errors follow a consistent format:

json
{
  "code": "UNAUTHORIZED",
  "message": "Invalid or missing API key",
  "requestId": "req_abc123",
  "retryable": false,
  "details": null
}
HTTP StatusCodeDescription
400VALIDATION_ERRORInvalid request body / schema constraints violated (returned by core's MnemoError(VALIDATION_ERROR, ..., 400) path)
401UNAUTHORIZEDMissing or invalid API key
403FORBIDDENAPI key lacks permission for the requested action (NOT raised on cross-tenant reads — those return an empty result set)
404NOT_FOUNDReferenced atom / domain does not exist
422VALIDATION_ERRORFastAPI/Pydantic-level validation failure (raised before reaching the route handler)
429RATE_LIMITEDToo many requests. Check Retry-After and X-RateLimit-Reset headers
500INTERNALServer-side error (may be retryable)

The codes above are the exact strings the API returns in the code field of the error body — match them with === / == in agent code, not by substring. There is no AUTH_INVALID or INTERNAL_ERROR code; older docs that mentioned them are wrong.

Rate Limits

Rate limits depend on your plan:

PlanRequests/minQueries/dayAtoms
Free601,00010,000
Pro60050,000500,000
Team3,000500,0005,000,000

Rate limit headers are included in every response:

text
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1712345678