Korely

Users & agents

Audit log

What happened in your project, and what your agents read: one event per call that ran, newest first.

GET /v1/audit

SDK: korely.audit(...), and korely.iter_audit(...) to read every page. The Glossary defines the audit log and the other words used across the docs.

"Who wrote this memory, and what did the agent know when it decided?" Filter by user_id to get the events attributed to one end user: writes, edits, fact writes, corrections and forgets, end-user erasures, reads of one memory, and every read made with that user_id, with the memories and facts it returned. A read made without a user_id, and the event that queues a batch, carry user_id null: find them by target_id or in read. Each memory a batch imports has its own write event (actor worker, meta.batch the job id) with its end user. A read lists ids. To see what the store knew at that moment, read with known_as_of set to the event's ts: Get facts returns the facts as the store knew them then, and Get context the block it could have built. as_of answers another question: what was true then, as the store knows it now.

The log records ids, counts and short labels, never the text of a memory, a fact or a query. Erasing an end user or an agent namespace therefore removes its content for good, and the log still shows that it happened. Forgetting a single memory is recorded as erase too, but keeps the memory and its facts as history. Events are kept for 400 days.

This endpoint returns the events filed under your key's project: every call made with a key, key_create, key_change, a project's create, rename, archive and unarchive (setting_change), a key disconnected by an app (key_revoke), and reads made from the dashboard on this project's data (actor dashboard).

Since 1.0.12, a change made in the dashboard or with an admin key is filed in the project of what it changes (a fact, a key, a webhook or an alias), with that item's end user when it has one. This covers a fact forgotten or corrected, a key revoked, a webhook made, deleted or switched on, a webhook's test delivery, and an alias made or deleted. Opening an event in the dashboard's Audit log to see its memories and facts is a read, and it is filed the same way, in the project and with the end user of each memory and fact it shows. Up to 1.0.11 these were filed under no project (a test delivery was not filed at all), so this endpoint did not return them, and a fact, an alias or the ids an event lists had no end user, so ?user_id= did not find them. A list read in the dashboard is filed with an end user only when the list asked for one: the Memories page of a project with several end users is filed with none, so ?user_id= does not find it.

Events with no project are not returned to a key. Examples: login, logout, the model settings, a webhook for every project, an end user erased in every project, a project deleted, and the reads made in the dashboard with All projects chosen. The dashboard's Audit log lists them under All projects.

For an event made in the dashboard, the log also keeps the name the person signed in with (meta.operator, often an email), and the dashboard's Audit log shows it. Since 1.0.12 this endpoint leaves it out: every key of the project can call this endpoint, so it does not show who signed in to the dashboard.

Authentication

HTTP header, required: Authorization: Bearer kor_live_.... The key needs the memories:read permission (the API calls it a scope). Reading the log does not count against your query quota, and the read is not itself written to the log. It does count against the rate limit.

A key sees only the events of its own account and its own project. A key whose project was deleted falls back to the account's Default project and reads its events.

Query parameters

ParameterTypeRequiredDescription
user_idstringOptionalOnly the events that touched this end user. 1 to 255 characters. After an erasure, ask with the original id: the pseudonym is found for you.
actionstringOptionalOnly the events with this action: read, write, fact_write, fact_invalidate, erase, key_create, key_revoke, key_change, setting_change or tenant_create. An open string, max 32 chars: an unknown action returns an empty page, not an error.
sincestringOptionalISO 8601 date or datetime, inclusive: events at or after this moment (2026-10-01 or 2026-10-01T00:00:00Z); a value with no offset is UTC. At most 64 characters. Give the offset as Z, or encode + as %2B.
untilstringOptionalISO 8601 date or datetime, inclusive: events at or before this moment. At most 64 characters.
limitintegerOptional1 to 1000. Default 100.
offsetintegerOptionalDefault 0. Page with limit and offset; total counts every match. At most 9223372036854775807 (2^63-1); a larger one answers 422.

Example request

Terminal window
curl "https://api.korely.ai/v1/audit?user_id=customer-4812&limit=50" \
-H "Authorization: Bearer kor_live_..."

Response

200 OK. The events, newest first, and how many match. The order is ts descending, then the event's internal id descending, so two events in the same instant keep one order and paging with offset is stable: a page neither repeats nor skips an event that was already there.

{
"events": [
{
"ts": "2026-10-02T09:14:31.218000Z",
"actor": "rest",
"action": "read",
"result": "ok",
"user_id": "customer-4812",
"target_id": null,
"meta": {"endpoint": "context", "memories_read": 3, "facts_read": 2},
"ip": null,
"read": {"memories": ["mem_8f2c1a", "mem_41d0e7", "mem_c9a0b2"], "facts": ["fct_a1", "fct_b7"]}
},
{
"ts": "2026-10-02T09:12:05.004000Z",
"actor": "rest",
"action": "write",
"result": "ok",
"user_id": "customer-4812",
"target_id": "mem_c9a0b2",
"meta": {"endpoint": "memories:add"},
"ip": null,
"read": null
}
],
"total": 2
}
FieldTypeDescription
events[].tsstringISO 8601 time of the event.
events[].actorstringWho acted: rest (the API), mcp (the agent MCP server), dashboard (you, in the dashboard), manage (the command line of an install), worker (Korely's background worker), oauth (an app connected over OAuth: its key made, renewed or revoked) or install (a change to the whole install, filed in every account's trail).
events[].actionstringread, write (a memory added, updated or batch-imported), fact_write (a fact written or corrected, or a name declared for an end user), fact_invalidate (a fact forgotten by hand, from the dashboard or the admin API), erase (a memory, an end user, an agent namespace or a fact forgotten, or a project deleted with its data), key_create, key_revoke (a key revoked in the dashboard or with an admin key, filed in the key's project since 1.0.12, or a key disconnected by an app), key_change (a key moved to another project), setting_change (a setting changed in the dashboard or with an admin key:meta.setting says which, meta.op how), tenant_create (the account created). Read the field as an open string: new actions can appear.
events[].resultstringok; error when a call was refused after the key was checked, for example: the memory, fact or job is not reachable with the key (404), a stale expected_updated_at or a fact no longer current (409), a declared name already taken (409), a model a fact write needs or the search backend gave no answer (503), a confined key asking for an end user outside its list or deleting an agent namespace (403); meta.code says which. Not recorded: a bad key or scope, a malformed request, the rate limit, the monthly quota and the agent cap.
events[].user_idstring · nullThe end user the event touched. After the end user is erased, the events carry a keyed pseudonym (erased: followed by 32 hex characters) instead of the id; ask with the original id and they are found.
events[].target_idstring · nullWhat was acted on: a memory (mem_), a fact (fct_), a batch job (job_), an agent namespace (the agent_id itself, with meta.endpoint agents:delete), a key, a project, a webhook or an alias (its id). null for an end-user erasure and for list and search reads.
events[].metaobject · nullCounts and labels: the endpoint, how many memories and facts a read returned, and the as_of and known_as_of a read asked for. For a correction, a close or a forget of a fact or a memory: the counts of what changed (facts_closed, facts_deleted, facts_invalidated, status), and facts_reopened when deleting a memory or an agent namespace made a fact true again and the count is not zero. For setting_change: meta.setting is project, webhook or alias (and, on a Self-hosted install, operator, install_admin, provider_key or writer; an app's OAuth consent is filed as oauth_consent with its scopes and no op), and meta.op is create, rename, archive, unarchive, delete, enable (a webhook switched back on), test (a webhook's test delivery, with delivered and status), set, clear, grant, revoke or password. A project's rename, description or region change is logged as setting project, op rename; when the request sent a region, meta.region holds the value sent (eu or global); when the request set the region to null (Global on the Cloud), meta has no region key. A project deleted with its data is filed as action erase with meta.setting project and op erase. Read both as open strings: new values can appear. For key_change: op is move, and the event is filed under the project the key moved to. An event made by a person signed in to the dashboard has actor dashboard; the log also stores their dashboard username as operator, but since 1.0.12 this endpoint leaves operator out of meta (the dashboard's Audit log shows it). The same changes made with an admin key are filed with actor rest and no operator. Never a webhook address or an alias name.
events[].ipstring · nullnull on every event. The address a person signed in from is recorded with the login event, which this endpoint does not return.
events[].readobject · nullFor a read: the ids it returned, memories and facts, at most 100 of each (the full counts are in meta).
totalintegerEvery event that matches the filters.

Errors

StatusCodeCause
401invalid_keyMissing or invalid kor_live_ key.
403forbiddenThe key lacks the memories:read scope, or it is confined to some end users and user_id is outside its list. Without user_id, a confined key sees only the events of its own end users.
422invalid_requestsince or until cannot be read as a date or datetime, limit is outside 1..1000, offset is below 0, user_id or action is empty (leave the parameter out instead) or holds a NUL byte, user_id is longer than 255 chars, or action longer than 32.
503unavailableThe key could not be checked because the database did not answer, or the request waited past one of the store's deadlines. Retry after the seconds in Retry-After.
429rate_limit_exceededPer-plan minute, hour or day request ceiling exceeded for the account (all its keys share the windows); the message names the window, and Retry-After gives the seconds until it resets. The log never answers quota_exceeded: it does not count against the query quota.

Find the record of an erasure

An end-user erasure (Erase a user) is the event with action erase, user_id the pseudonym, target_id null and meta.endpoint users:delete, with the counts. Filter with action=erase and the original user_id. Deleting one memory (memories:delete) or forgetting one fact (facts:forget) also gives action erase, so read meta.endpoint.

The event does not carry the audit_id that the erasure returned, and no call reads that id back: keep it from the response. The event does not say which key made the call either.

Self-hosted too. Korely self-hosted answers GET /v1/audit with the same parameters.