MemNexus
Concepts

Privacy & Security

How MemNexus protects your data — authentication, encryption, isolation, and data ownership.

Your memories are personal. MemNexus is designed to keep them private and secure.

Authentication

All API access requires authentication via API keys. Keys follow the format:

cmk_live_<id>.<secret>
  • The <id> portion identifies the key
  • The <secret> portion is hashed and validated server-side
  • Keys are passed as Bearer tokens in the Authorization header

API keys are never stored in plaintext. Only the hashed secret is persisted.

Data isolation

By default, a request reaches only the data belonging to the account its API key was issued to. That default has exceptions, and they are enumerated below rather than summarized — if you find a customer-facing path that returns another user's data and is not on the list, the list is wrong and we want to hear about it.

  • Separate graph namespace — Your memories, facts, topics, and entities exist in your own space

  • Query isolation — Search returns your own memories. The search endpoints scope every query to the user the API key belongs to, so a memory another user shared with you does not appear in your search results; you reach it by fetching it directly (GET /api/memories/:id)

  • Cross-user access is off by default, and these four paths turn it on — Requests are scoped to the user their API key belongs to unless one of the paths below applies. All four are in production code today. The protections differ from path to path, so read the one that applies to you rather than the summary:

    1. You shared it. A memory's owner can share it with named users or with everyone in their organization (POST /api/memories/:id/share; DELETE on the same path revokes). A user who has been granted access can then read that memory, and read paths check for the grant on every request. Only the owner can share.
    2. An organization admin fetched one memory by ID. On GET /api/memories/:id, an admin or owner of an organization can read a member's memory without any grant from the owner. On this path the query compares the memory's creation time to the reader's membership join time, so memories created before the member joined the organization are not returned; and the read is written to an audit log naming the reader, the owner, and the memory.
    3. An organization admin listed members' memories in bulk. GET /api/memories/org/:orgId returns memories belonging to every member of that organization, decrypted, up to 100 per page, with an optional ?userId= query parameter that narrows the results to one named member. The caller must be an admin or owner of the organization, but the credential is an ordinary customer API key with ordinary read permission — no separate administrative key is involved. Two protections that apply to path 2 do not apply here. There is no join-date comparison on this path, so memories a member created before joining the organization are returned. And this path writes no audit-log entry, so a bulk read of members' memories leaves no audit record: nothing on this path carries the audit.admin_access structure that makes path 2's single-memory read queryable as an administrative access. The read is not invisible, though — global request logging records the reader's user ID and the request path, so application logs show that this admin called the org-listing endpoint on this organization. Those log lines omit the query string, so they do not show which member was targeted, which memories were returned, or how many, and nothing in them marks the read as a privileged cross-user one. The one filter it does apply is that memories are omitted when their owner's account is in a deletion state.
    4. An operator ran a bulk job. Bulk administrative operations that run across users (for example re-generating embeddings) exist. They are restricted to operators authenticating with a separate administrative key — not a customer API key — and they write an append-only audit record identifying the operator and the operation.

    If your organization has admins, treat paths 2 and 3 as the ones that matter: an admin can read what members store, and on path 3 that read is neither bounded by join date nor audited.

API Gateway security

All traffic flows through the API Gateway, which provides:

  • Authentication — Validates API keys before requests reach the Core API
  • Rate limiting — Prevents abuse and ensures fair usage
  • Request routing — Only exposes intended endpoints
  • TLS termination — All connections use HTTPS

Data in transit

All API communication uses HTTPS (TLS 1.2+). This includes:

  • Client → API Gateway
  • MCP Server → API Gateway
  • SDK → API Gateway

No data is transmitted in plaintext.

Data at rest

Memories are stored in the graph database with:

  • Field-level encryption — Sensitive fields, including memory content, are encrypted by the application before they reach the database, using AES-256-GCM-SIV with a per-user data key. Each user's data key is itself encrypted ("wrapped") by a key-encryption key held in a managed key vault. The database stores ciphertext for those fields. Coverage is not total: some fields are stored unencrypted by design — the plaintext search index is one — so treat this as encryption of sensitive fields, not of every field
  • Vector embeddings — Generated by an external embedding provider and stored alongside memories
  • Third-party access to stored data — Text derived from your data reaches the external providers we use to run the product: memory content when a memory is created; claim text extracted from your memories during search; and stored memory content when you request an AI-generated briefing — see External processing of memory content. We do not sell that data, and we do not share your stored memories, embeddings, or extracted graph data with anyone else

External processing of memory content

Text leaves MemNexus at several points. Two are part of the memory pipeline: when you create a memory, its content is sent to external providers for vector embeddings and for knowledge extraction; when you search, your query text is sent to an external embedding provider, and statements extracted from your stored memories may be sent to an external language-model provider. Outside that pipeline, your search query text is also sent to a third-party product-analytics service. Who those providers are, and the data-handling terms that apply to each, are published on our subprocessors page.

When you create a memory

When you create a memory, its content is sent to external providers for two distinct purposes.

1. Vector embeddings — for search

  • What's sent: Memory content text
  • What's returned: A 1024-dimension float vector
  • What's stored: The vector, alongside your memory in the graph database. Vectors are also cached so that identical text does not have to be re-embedded: in the API server's process memory for up to 1 hour, and in a shared Redis cache for 7 days by default. Cache entries are keyed by a SHA-256 hash of the model name and the normalized text, and hold only the vector — the memory text itself is not written to the cache. These caches expire on their own schedule and are not covered by the retention table below

2. Knowledge extraction — for distillation, summaries, and the knowledge graph

  • What's sent: Memory content text
  • What's returned: Structured output — distilled content, summaries, claims (the short declarative statements described under Claim comparison below), and the entities, facts, and relationships that make up your knowledge graph
  • What's stored: The distilled content and the extracted graph data, alongside your memory

A keyword, semantic, or hybrid search sends out your query text. Depending on what your results touch, it can also send out short factual statements that were extracted from your stored memories — see Claim comparison below.

  • What's sent: The text of your query. Matching memories by meaning rather than by keyword requires the query as a vector, so the query text is sent to an external embedding provider to be embedded — a separate call from the one made on your memory content when a memory is created: it sends the text as a query rather than as a document, and the provider is not necessarily the same one
  • What's returned: A 1024-dimension float vector for the query
  • What's stored: The query vector is used to rank your results, and passes through the same embedding caches described above — so an identical query repeated inside the cache window can be served from cache instead of being sent to the provider again. Separately, the search itself is recorded in our own database: each search writes a row holding your query text (up to the first 2,000 characters), your user ID, your organization ID, and the IDs and relevance scores of the memories returned. Your query text also appears in our application logs. Both of these are our own systems, not an external provider. Retention of these search-interaction rows is not covered by the retention table below
  • Also sent to analytics: Your query text is sent to a third-party product-analytics service as a property on search events, along with the previous query in the same session and the search method used. This is a separate flow from the embedding call above, and it is not limited to semantic search
  • Claim comparison — also sent: Search results carry claim groups, which mark whether the claims behind your results agree or conflict. Claims are short declarative statements that the knowledge-extraction step above derives from your memory content — your memory text one step removed, in natural language, rather than the raw memory. When a search surfaces a pair of claims that has not been compared yet, the text of both claims and their dates are sent to an external language-model provider, which returns a score for how far the two agree. Points worth knowing: this is on by default on both search endpoints, so it applies unless you set includeClaims to false; it is not limited to semantic search, and a searchMethod=keyword search reaches the same step; the pair can include a claim belonging to a memory that is not in your results, because the comparison follows up to 20 neighboring claims in the graph for each claim it starts from; a pair whose score is saved is not sent again, while a pair we fail to score — or fail to record the score for — stays unscored and may be sent on a later search; and each request is bounded, by default to at most 50 pairs and a scoring budget of about three seconds, with anything left over deferred to a later search. A search that surfaces no uncompared pairs does not send claim text. The provider used for this comparison is not necessarily the same one used for knowledge extraction
  • When the embedding call doesn't happen: A search that does not use vector matching does not require a query embedding. The main case is searchMethod=keyword, a supported value of the searchMethod parameter on the search endpoints; a lookup restricted to a time range is another. If the embedding provider is unavailable, semantic search falls back to a keyword search inside our own database. This covers the query-embedding call only, and does not mean nothing else leaves MemNexus on that search: the analytics flow and the claim comparison described above both apply to keyword searches as well

AI-generated briefings send more, and send it more directly. This is a difference of degree from the claim comparison above — both send text derived from your stored memories to an external language-model provider at the time you query. The digest endpoints (POST /api/memories/digest and /digest/stream), which sit behind mx memories digest and its mx memories recall alias and behind the recall MCP tool, gather the memories matching your query, decrypt them, and send that memory content itself — not statements extracted from it — to an external language-model provider so it can synthesize the briefing. They also run only when you ask for a briefing, rather than as part of an ordinary search.

For the current list of external providers, what each one processes, and their data-handling terms, see the subprocessors page.

API key management

Best practices

  • Rotate keys periodically — Create a new key, update your systems, delete the old one
  • Use separate keys per environment (dev, staging, production) and per application
  • Set expirations on temporary keys
  • Never commit keys to version control
  • Use environment variables in CI/CD, not config files

Key lifecycle

# Create a new key
mx apikeys create --label "Production v2"

# Verify it works
mx auth login --api-key cmk_live_new.key
mx auth status

# Delete the old key
mx apikeys delete old_key_id --force

Data ownership

Your data belongs to you:

  • Export — Retrieve all your memories via the API or CLI
  • Delete — Remove individual memories or your entire account
  • No vendor lock-in — Data is accessible via standard REST API

Export your data

# Export all memories as JSON
mx memories list --format json --limit 10000 > my-memories.json

# Export all facts
mx facts list --format json --limit 10000 > my-facts.json

Export while your account is active. Once you request account deletion, reads are blocked and export is no longer available — see What happens when you request deletion.

Data deletion & retention

MemNexus supports account deletion in compliance with GDPR Article 17 (Right to Erasure) and CCPA.

How to delete your account

You can request account deletion through:

  1. Customer Portal — Go to Profile and click "Delete Account", then confirm with your email address
  2. API — POST /api/users/me/deletion with { "confirmationEmail": "your@email.com" }

What happens when you request deletion

  1. Grace period (30 days) — Your account enters a 30-day grace period. Thirty days is a floor in the code, not just a default: the window can be configured longer, but a shorter value is raised back up to 30. During this time:

    • Your account is in read-only mode — no new memories or data can be created
    • Export your data before you request deletion. Requesting deletion puts your account into a deletion state, and every read route runs a guard that looks that state up on each request and returns 404 while it is set — the bulk export endpoint included. The block rests on that guard, which reads your account record directly, not on your credentials being withdrawn: revoking your API keys is also triggered by the deletion request, but it runs as a background task, so do not rely on it as the thing that stops reads. Plan to export before you make the request
    • You can still sign in to the Customer Portal to see the deletion status and cancel the deletion, which restores full access. Expect to create a new API key afterwards: the deletion request triggers revocation of your existing keys
  2. Permanent deletion — After the grace period, a background job permanently deletes:

    • All memories, conversations, facts, entities, patterns, and artifacts
    • Your API keys
    • Your identity from our authentication provider (WorkOS)
    • Your billing information from Stripe
    • A confirmation email is sent to your address
  3. Audit record — A pseudonymized audit record is retained for compliance purposes. It contains:

    • A SHA-256 hash of your user ID and email (not reversible to your identity)
    • Counts of deleted data (e.g., "50 memories deleted")
    • Timestamp of deletion
    • No personal data or memory content

Data retention after deletion

Data typeRetention after deletion
Personal data (name, email, profile)Immediately deleted
Memories, facts, conversationsImmediately deleted
API keysImmediately revoked and deleted
Stripe customer recordImmediately deleted
WorkOS identityImmediately deleted
Pseudonymized audit recordRetained indefinitely for compliance
Server logsRetained for 14 days, then purged
Database backups (disaster-recovery snapshots)Up to 90 days — see below

Database backups. Production database snapshots are taken every 6 hours and kept for 90 days, then deleted automatically. Account deletion acts on the live database only, so a snapshot taken before your deletion request still contains your data until that snapshot ages out — up to 90 days after the snapshot was taken. These are disk-level snapshots held for disaster recovery: nothing serves API traffic from them, and restoring one is a manual operation. Like the embedding caches described above, they expire on their own schedule rather than at deletion time.

Re-registration

After deletion, you can create a new account with the same email address. The new account starts fresh with no connection to the previous account.

MCP server security

The MCP server is a stateless translation layer:

  • No direct database access — All requests go through the authenticated API Gateway
  • Where your API key is stored — mx auth login writes the key to a local config file. The location is not a fixed absolute path: the CLI resolves a config directory from XDG_CONFIG_HOME when that variable is set, and falls back to ~/.config when it is not, then appends configstore/@memnexus-ai/cli.json. On a machine with no XDG_CONFIG_HOME set, that is ~/.config/configstore/@memnexus-ai/cli.json. The file is created with POSIX mode 0600 (readable only by your user) — a POSIX permission bit, so it has no effect on Windows, where the file's protection is whatever your user profile directory grants. The key is stored in plaintext — the file is not encrypted at rest, so anyone who can read that file, or a backup or disk image containing it, has your key. If you would rather not persist it, set MX_API_KEY in the environment instead: the CLI reads the environment variable first and it takes precedence over the stored key. The MCP server itself holds no credential state; it forwards the key it is given
  • Two ways to connect, both reaching our infrastructure — Agents that support remote MCP connect directly to the hosted MemNexus MCP server at https://mcp.memnexus.ai/mcp. Agents configured with mx mcp serve run a bridge on your machine, but that bridge is a stdio-to-HTTP proxy: it forwards every request to the same hosted server. In both modes your requests and memory content reach MemNexus infrastructure and are processed there — see External processing of memory content
  • Open protocol — MCP is an open standard you can audit