openmemory
Docs

Your own OpenAI key

Use your own OpenAI key for meaning search. The embedding calls are billed to your OpenAI account, and the key is stored encrypted and can't be read back.

By default, embeddings for meaning search are made by Cloudflare Workers AI, within a daily limit shared by every space. When that limit is reached, recall falls back to word search until the next UTC day. With your own OpenAI key, your space has its own allowance: embedding calls are billed to your OpenAI account, at $0.02 per million tokens for text-embedding-3-small, and don't use the shared limit.

Your facts and recall questions then go to OpenAI under your account. Stored embeddings still count towards the service's shared limit.

Set your key

Create a key just for this. In the OpenAI dashboard, make a separate project, set a hard spend limit on it (an alert on its own doesn't stop requests), and give the key only the permissions embeddings need, if your dashboard offers that. A leak is then contained to that project. OpenAI's enforcement can lag slightly, so check your usage too.

Set it yourself, from your own terminal, reading the key from an environment variable. Don't paste it into a chat with your agent: that puts it in the model's context and transcripts, which is why there is no MCP tool for this.

bash
curl -s -X PUT https://api.openmemory.sh/v1/space/embeddings \
  -H "Authorization: Bearer $OPENMEMORY_KEY" -H 'content-type: application/json' \
  -d "{\"provider\":\"openai\",\"api_key\":\"$OPENAI_API_KEY\"}"

In PowerShell:

powershell
$body = @{ provider = "openai"; api_key = $env:OPENAI_API_KEY } | ConvertTo-Json
Invoke-RestMethod -Method Put https://api.openmemory.sh/v1/space/embeddings `
  -Headers @{ Authorization = "Bearer $env:OPENMEMORY_KEY" } -ContentType "application/json" -Body $body

Then check it with GET /v1/space/embeddings, which shows only the key's last four characters.

How the key is protected

ProtectionWhat it means
Encrypted with two secretsAES-256-GCM, with a key derived from a server secret (not in the database) and your space key (only a hash of it is stored). A copy of the database can't open it, and neither can the server secret alone.
Opened only by your requestsIt can only be decrypted during a request made with your space key, and only in memory for that request. Scheduled jobs can't use it.
Write-onlyNo endpoint returns it, and export leaves it out. GET /v1/space/embeddings shows only its last four characters.
One destinationIt is only ever sent to https://api.openai.com. There is no setting that could send it anywhere else, and redirects are refused.
Kept out of logsThe service doesn't log request bodies, per-request logs are turned off, and OpenAI's error messages, which can quote part of a key, are never logged or returned.
Capped useAnyone holding your space key could run up embedding calls, though never read your OpenAI key. Each space is limited to about 2 million tokens a day, roughly $0.04 at OpenAI's $0.02 per million for text-embedding-3-small.
Can't test stolen keysAttempts to set a key are limited to 10 per space per day and 10 per IP address per hour.

What this can't protect against: the server has to use your key in memory to call OpenAI, so someone who took over the running service could capture it during a request. Self-host if that's outside what you can accept, and keep the spend limit on the project either way.

If something goes wrong

If you think the key leaked, revoke it at OpenAI first, then run DELETE /v1/space/embeddings, which deletes the encrypted copy and goes back to the default embeddings. If OpenAI refuses the key, recall falls back to word search and GET /v1/space/embeddings shows status: "rejected" until you set a new one. If you lose your space key, the stored key can never be opened again; revoke it at OpenAI. Deleting the space deletes it too.

Switching

Your facts are re-embedded after a switch, a batch at a time as you use recall and context, because only your own requests can open the key. Until then, those facts are found by words only.