Users & agents
Erase a user
Permanently erase every memory and fact of one end user in the key's project, in a single call. Korely keeps a receipt that holds counts and a pseudonym, never the content.
/v1/users/{end_user}/memories
SDK: korely.delete_all(user_id=end_user). Use it when one of your
customers asks you to erase their data. The step-by-step guide, with a test
user, is Forget a user. The
Glossary defines the words used across the docs.
This call deletes for good. Try it on a test end user first.
This is a physical delete. The rows are removed from the live database, and the content cannot be read back through the API, whatever parameter you send. On the Cloud, encrypted nightly backups keep a copy for up to 35 days.
What Korely keeps carries no erased content and never the id itself, only a
pseudonym of it: a code of erased: and 32 hex characters that Korely computes from the id with a secret key. That is
enough to show that the erasure happened:
- the erasure receipt, whose id is the
audit_idof the response; - an
eraseevent in the audit log; - the audit-log rows of calls that named this end user (kept for 400 days), earlier erasure receipts, and the records of webhooks already delivered, all relabelled with the same pseudonym.
GET /v1/audit?user_id=<the same id> computes the pseudonym
and finds the trail rows. A Self-hosted install with no SECRET_KEY setting has no pseudonym key: the id
is dropped and nothing replaces it, so the proof is the audit_id.
Authentication
HTTP header, required: Authorization: Bearer kor_live_.... The key must carry the memories:write permission (the API calls it a scope), and belong to the project that holds the end user.
Path parameter
| Parameter | Type | Description |
|---|---|---|
end_user | string | The end-user namespace to erase, the user_id exactly as written. Every memory and fact scoped to this value in the key's project is deleted. Match it character by character, case and spaces included. Percent-encode it as one path segment (acme/42 is acme%2F42); any stored id is accepted. An unknown end_user is not an error: it returns 200 with zero counts and a new audit_id, so a mistyped id looks like success. An empty one, one longer than 255 characters, one with a NUL byte, or one that is an erased pseudonym (erased: and exactly 32 lowercase hex characters), is refused with 422 invalid_request. |
This endpoint takes no query parameters and no request body.
Example request
curl -X DELETE https://api.korely.ai/v1/users/customer-giulia-4812/memories \ -H "Authorization: Bearer kor_live_..."Response
200 OK. The end-user namespace that was erased, the counts of
what was deleted, and the id of the erasure receipt.
{ "user_id": "customer-giulia-4812", "memories_deleted": 14, "facts_deleted": 31, "erasure": "permanent", "audit_id": "aud_5f0c2d9e8b7a4c1d9e3f6a2b1c0d4e8f"}| Field | Type | Description |
|---|---|---|
user_id | string | The end user that was erased (echoes the path parameter). |
memories_deleted | integer | Count of memories physically deleted, memories forgotten earlier included. |
facts_deleted | integer | Count of facts physically deleted, closed ones included. |
erasure | string | Always permanent: nothing erased here can be read back through the API. |
audit_id | string | Id of the erasure receipt Korely keeps (counts and a keyed pseudonym of your end-user id, never content): aud_ and 32 hex characters. It comes once, in this response, and no call reads it back: store it with your own erasure record. |
Up to version 0.1.42 the response also carried memories_forgotten
and facts_invalidated, the same two numbers under older names.
From 0.2.0 they are gone: read memories_deleted and
facts_deleted.
Errors
| Status | Code | Cause |
|---|---|---|
401 | invalid_key | Missing or invalid kor_live_ key, Invalid or missing API key: ..., then what is wrong. |
403 | forbidden | The key lacks the memories:write scope, API key missing required scope(s): memories:write; or the key is a confined key that does not cover this end user. |
422 | invalid_request | end_user is empty, longer than 255 characters, holds a NUL byte, or is an erased pseudonym (erased: and exactly 32 lowercase hex characters). |
429 | rate_limit_exceeded | The account hit its rate limit. The response carries a Retry-After header. |
503 | unavailable | The database is busy with another change to the same data. Retry after the seconds in Retry-After. |
On every error above, nothing was erased. Branch on code, not on message.
Notes
- Stop writing for that id first. A write after the call creates the end user again.
- One transaction. Memories, facts, the names declared for the end user and the vocabulary Korely learned from its facts are erased in one database transaction. Items of
POST /v1/batchimports that name the end user are scrubbed from the import, queued or finished. - Not erased. Memories written without a
user_id, or under another id, stay even if they name the person. Copies outside Korely are yours: your logs and databases, and the model provider that read the text to extract facts. - Every
agent_id. The call covers the end user's data under all agent namespaces of the project. - Distinct from deleting one memory.
DELETE /v1/memories/{id}forgets one memory (it drops out of every read and its row stays) and, witherase=true, erases that one memory for good (REST only; the SDKs'delete()does not send it). - Scoped to the key's project. If the same end user lives in several projects, call it once per project, with that project's key. The same id in another project stays intact.
- Names declared in other projects. The names declared with Declare a name are erased in the key's project. A name from before version 0.2.0 that Korely could not place in a project goes with the last erasure of the person, when nothing of them is left in another project. Names declared in another project of the account stay.
- No 404, and a timeout is safe to repeat. If the first call succeeded, the second returns zeros and a new
audit_id; the firstaudit_idcannot be read back. - Two records of the call. Each call writes the receipt (
audit_id) and aneraseevent in GET /v1/audit, with the counts inmeta. The event does not carry theaudit_idand does not show which key made the call. Itsuser_idis the pseudonym (erased:...); askGET /v1/audit?user_id=<the id>and it is found. Deleting one memory or forgetting one fact also writes aneraseevent: yours is the one whosemeta.endpointisusers:delete. - Keep your own receipt. Store the
audit_idand the time of the call. - Do not build the list to erase from List users. It shows only end users with active data, one page at a time. Build the list from the ids you wrote.
Related
- Forget a user, guide, the narrative walkthrough with context.
- List users, see which end users have active data.
- Audit log, where the
eraseevent appears. - Add a memory, the write path that creates them.