Platform
Data & governance
Where your agents' memory lives, who can touch it, and how to erase it.
EU data residency
Your stored memory lives on our own infrastructure in the EU. It is stored in the EU, never replicated to the US. EU data residency applies on every tier, including the free Hobby plan, and requires no configuration on your part.
Storage is in the EU, and so are the embeddings: an open embedding model
(EmbeddingGemma) runs on our server in Helsinki and turns memories, facts
and search queries into vectors there. The language model that reads a
memory into facts depends on the project's region:
the Gemini API (Google, United States, under the EU Standard Contractual
Clauses and a DPA) in the default global region, gpt-oss-120b
on Scaleway in Paris in the eu region. Either way it sees
text: the memory you write, to extract its facts; the earlier facts a new
one is compared with, for the contradiction check; and a new relation
phrase, the first time your project uses it. A search or context query
never reaches a language model. Neither provider trains its models on
that text. The derived outputs, facts, embeddings and graph edges, are
stored only in your account's namespace, in the EU. The full list is on
the Security page.
EU residency applies to every namespace by construction, your facts,
embeddings, and graph edges are written only to EU-hosted storage. A
GET /v1/ping probe confirms the API is reachable and echoes
your key's tier, scopes, storage region (region) and the
region of its project (processing_region):
curl https://api.korely.ai/v1/ping \ -H "Authorization: Bearer kor_live_..."# {"ok":true,"tier":"hobby","region":"eu-hel1","processing_region":"global","scopes":["memories:read","memories:write"]}Read-only and write-only keys
A key reads and writes unless you choose otherwise. On the
API Keys page of the dashboard, Access in
Create API key gives a key only memories:read
(search, context, lists and the audit log: a frontend or a support tool)
or only memories:write (add, change and forget: an import
pipeline that never reads the memory back). A call outside the key's
scopes is refused and reads or writes nothing: 403 forbidden
on REST, a forbidden: error from the MCP tool. A key keeps the scopes it was made with: for
different ones, make a new key and revoke the old.
Regions
Each project has a region. You choose it on the Projects
page of the dashboard, when you create a project or later. An account made
with POST /v1/agents/init has no dashboard login: it picks the
region of its Default project at signup, with
"processing_region": "eu" in the body
(Sign up as an agent), or later,
once you connect its key to a
login.
| Region | Model that reads your memories | Where it runs |
|---|---|---|
global (default) | Gemini | Google, United States |
eu | gpt-oss-120b | Scaleway, Paris, France |
- Storage and embeddings are in the EU in both regions.
-
In the
euregion no memory text reaches Google. When the EU model is unavailable, new memories are stored at once and their facts follow when it is back. They are never sent to theglobalregion. - A change of region applies to the next writes, including memories still waiting for their facts. Facts already written stay as they are.
-
The region says where your memories are read, not where they are
stored.
GET /v1/pingreports both:regionis the storage location,processing_regionthe region of the key's project.
Namespaces & scoping
Every call is scoped by your account and by the project of the key first, then by the namespace parameters you pass:
-
user_id, your end user. The unit of isolation; unlimited on every tier. Choose any opaque string (a database ID, a hashed email, a UUID) of 1 to 255 characters, without/or control characters and other than.or..: the erase call addresses it as one URL path segment. Other values are refused with422 invalid_request. -
agent_id, one of your apps or agents. Plans cap the number of distinct agent IDs (Hobby: 2, Developer: 10, Team: 100, Scale: 500). Passing an unknownagent_idpast your plan's limit returns403 agent_cap_exceeded. -
run_id, a single session or conversation turn. Useful for isolating memories that should not persist across runs.
The scope is enforced server-side on every query. One customer's memories
can never surface in another's results, by construction, not by prompt
discipline. The GET /v1/users endpoint lists every
user_id held in the key's project, so you always know
exactly which end-user data you hold.
# List every end user in the key's project, with memory and fact countscurl https://api.korely.ai/v1/users \ -H "Authorization: Bearer kor_live_..."# {"users": [# {"user_id": "customer-4812", "memories": 18, "facts": 9, "last_active": "2026-06-15T..."},# {"user_id": "customer-7091", "memories": 4, "facts": 2, "last_active": "2026-06-14T..."}# ], "total": 2}Erasure (GDPR Article 17)
Forget everything Korely holds about one end user in the key's project, every memory and every fact, in a single call (one call per project):
curl -X DELETE "https://api.korely.ai/v1/users/customer-4812/memories" \ -H "Authorization: Bearer kor_live_..."# 200 OK# {"user_id":"customer-4812","memories_forgotten":18,"facts_invalidated":9,# "memories_deleted":18,"facts_deleted":9,"erasure":"permanent","audit_id":"aud_..."}
The call returns a receipt, memories_deleted,
facts_deleted, erasure: "permanent" and an
audit_id (memories_forgotten and
facts_invalidated are deprecated aliases with the same numbers),
so the erasure is itself provable. Erasure is not the bi-temporal supersede:
every memory and every typed fact about the user, superseded ones
included, is physically deleted, so no query surface (REST, SDK, CLI, or
MCP) and no include_invalidated flag can bring it back. What
stays is the audit record, with the counts and the user_id
but none of the erased content, for your own Article 5(2)
accountability. The endpoint is idempotent: erasing an unknown or
already-erased user returns 200 with zero counts, never an
error.
To forget a single memory (rather than an entire user), use
DELETE /v1/memories/{id}, or
korely.delete(id) in the SDK. It returns
{"id":"mem_...","status":"forgotten","facts_invalidated":N,"audit_id":"aud_..."}.
A repeat delete of the same memory, or a delete of an id that was never
created, returns 404 not_found. This is not an erasure: the
memory leaves every read, but its row stays and its facts stay as history
(include_invalidated still shows them). When a person asks
for their data to be gone, use the end-user erasure above, which deletes
the rows.
If you track which user_id values map to real people in your
own system, a one-call erasure is the complete Korely side of an Article 17
workflow, no support ticket, no waiting period.
API keys
Requests authenticate with a kor_live_ key in the
Authorization: Bearer header. Korely stores only a
SHA-256 hash of the key, the plaintext is shown exactly once, at creation,
and cannot be retrieved afterward. If a key is lost or suspected compromised,
revoke it in the dashboard and create a new one; the old key stops working instantly across
every surface (REST, SDK, CLI, MCP).
An invalid or missing key returns 401 invalid_key. Every Korely
error uses the same flat envelope, {"code": "<slug>", "message": "<text>"}
, so one catch block handles all of them:
{ "code": "invalid_key", "message": "Invalid or missing API key: no live key matches it (a revoked key stops at once); your keys are at https://agent.korely.ai/keys"}
Best practice: store your key in an environment variable
(KORELY_API_KEY) rather than hard-coding it. The SDK reads
this variable automatically. Never commit a kor_live_ key to
source control.
No training on your data
Your stored memories and facts are never used to train or fine-tune any model, Korely's own or any third party's. Embeddings are computed on our own server. The rest of the AI inference on the write path (entity extraction, relation typing) runs through DPA-covered sub-processors in data-processor mode, where they are contractually prohibited from using your data for their own model training. The processed outputs belong exclusively to your account namespace.
There is no opt-out toggle because there is no opt-in: training on customer data is not part of the data pipeline, by design.
Quota & rate limits
Plans carry monthly write and query quotas (see
pricing), each with a 10% grace on top. A
write that would take you past the plan's figure (with the month's top-ups) plus the grace returns
429 quota_exceeded and writes nothing; a read past the queries
quota gets the same answer. There is no surprise overage charge: on a paid
plan you can top up the month from the dashboard's Usage page, or upgrade
at any time. The quota 429 carries no Retry-After header; its
body says the month's figure, top-ups included (limit), what the month has used
(used) and when the count starts again
(resets_at, 00:00 UTC on the 1st):
{ "code": "quota_exceeded", "message": "Monthly write limit reached: 250 writes on the Hobby plan this month, plus a 10% grace. It starts again on 2026-11-01. To go on now, move to a paid plan at https://agent.korely.ai/usage (an account made with korely init connects its key to a login there first: https://korely.ai/docs/agent-signup/#connect)", "limit": 250, "used": 275, "resets_at": "2026-11-01T00:00:00Z"}
Short-term request bursts are handled separately. If you exceed the
per-minute, per-hour or per-day rate limit, you get a 429 that does carry a
Retry-After header, an integer number of seconds to wait
before retrying.
For the full security posture, encryption in transit, database access, sub-processor list, and compliance documentation, see the security page.
Related
- Security, encryption, sub-processors, compliance.
- API Reference, full endpoint and response schema docs.
- SDK Reference, Python and Node method signatures.
- CLI Reference,
korely delete-alland other commands. - Pricing, plan quotas and agent limits.