API Reference
Overview
One bearer header, JSON in and out, EU-hosted. The Python and Node SDKs cover these endpoints, the same call, three ways in.
Base URL: https://api.korely.ai. Every endpoint is under
/v1. Requests and responses are JSON; data is stored
in the EU. Prefer not to call HTTP directly? The
Python and Node SDKs cover these
endpoints (erasing a single memory with erase=true is REST
only), and there's an
interactive playground
generated from the live spec.
Authentication
Every request carries an Authorization header with your secret
key: Authorization: Bearer kor_live_.... The one exception is
POST /v1/agents/init, which mints your first key. Keys are issued when
you sign up as an agent. Keep the key
server-side: a full key reads and writes all memory in its project, and a
read-only one reads it all.
curl https://api.korely.ai/v1/ping \ -H "Authorization: Bearer kor_live_..."Scoping
Three optional strings scope every memory. You choose the values, within the id rule (user_id and agent_id: 1 to 255 characters, no /, no control characters, not . or .., not starting with erased:; run_id: 1 to 255 characters);
filters are additive (AND).
| Field | Identifies | Example |
|---|---|---|
user_id | Your end user. Unlimited on every tier. | "customer-giulia-4812" |
agent_id | Your application's namespace. | "support-bot" |
run_id | One session or conversation. | "chat-2026-06-17-a" |
Versioning
Korely is versioned by release number, today 0.2.1. Every
release and what it changes is in the changelog.
Korely follows one rule from version 1.0: nothing published is removed without a 2.0: an endpoint, a field or an error code published in a 1.x release stays in every 1.x release.
Errors
Errors return the matching HTTP status and a JSON body with a stable
code, a human message and detail (a
sentence, an object with code and message, or on a
validation 422 the list of fields that failed). A quota
429 carries limit, used and
resets_at inside detail; a 409 fact_not_current
also has current_fact_id at the top. Branch on code:
the wording of message may change.
{ "detail": "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", "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"}| Status | Code | When |
|---|---|---|
400 | confirmation_required | DELETE /v1/account without confirm=true. Nothing is deleted. |
401 | invalid_key | The Authorization header is missing, malformed, or the key is revoked. The message starts with Invalid or missing API key: and says which: no Authorization: Bearer header, a string that is not a key, or a key that matches no live key (unknown and revoked answer the same). On Self-hosted, kor_live_ is the Cloud's prefix, so the install refuses every kor_live_ key, on REST, MCP and the admin API, and its message says that keys minted there begin with kor_self_. |
403 | forbidden | The key lacks the scope the endpoint requires (e.g. memories:write), or it is confined to some end users and the request names one outside its list. |
403 | signup_disabled | POST /v1/agents/init while self-signup is closed. |
404 | not_found | No such resource in this workspace (also returned instead of 403, so membership isn't leaked). |
405 | method_not_allowed | The HTTP method is not supported for this path. |
408 | request_timeout | POST /v1/batch only: a body larger than 2 MiB did not arrive whole within 120 seconds. Nothing was done; send it again, or in smaller batches. |
409 | stale_write | expected_updated_at on PATCH /v1/memories/{memory_id} doesn't match the current record, another write landed first. |
409 | fact_not_current | PATCH /v1/facts/{fact_id} on a fact that is history (superseded, forgotten or ended). The body adds current_fact_id, the current fact to correct instead, or null when there is none. Nothing is written or counted. |
409 | account_has_login | DELETE /v1/account on an account you sign in to: close it from the dashboard (Account, Close the account) instead. |
409 | conflict | POST /v1/users/{end_user}/names with a name already declared for somebody else in that memory. Nothing changes. |
413 | payload_too_large | The request body is larger than the route takes: 2,097,152 bytes, or 78,245,152 for POST /v1/batch. Refused before the body is read, the key included; nothing was done. On the Cloud a body over 1 MB (80 MB for POST /v1/batch) is refused earlier with a bare 413, without this code. |
422 | invalid_request | Request validation failed: a missing field, a malformed value, a text with a NUL byte (on MCP the tool answers with an error: line instead), or a field the endpoint does not know. Request bodies refuse unknown fields (names are snake_case), except POST /v1/agents/init, which ignores them. message names the first offending field. |
429 | quota_exceeded | Monthly write or query quota used up, 10% grace included. detail carries limit (the plan's figure, top-ups included), used and resets_at (00:00 UTC on the 1st). Carries no Retry-After: read resets_at. A batch refused for the quota carries the same three fields. |
429 | agent_cap_exceeded | A new agent_id would take the account past its plan's named agents (names in queued batches count). Nothing is written. detail carries limit and used. |
429 | rate_limit_exceeded | Too many requests in the current minute, hour or day. This one does carry Retry-After. |
429 | signup_rate_limited | Too many new accounts from your network, or from everyone, in 24 hours. Carries Retry-After. |
500 | internal_error | The request failed on our side. Retry; if it keeps failing, tell us. |
503 | unavailable | The request waited more than 5 seconds for another one working on the same data. Nothing is applied; it carries Retry-After: 5. An erasure waits up to 60 seconds before giving this answer. |
503 | search_unavailable | The query could not be embedded: the embedding model did not answer, or your account already has four requests at the embedder (searches, context calls and the vectors of writes, running or waiting), or this one waited 20 seconds for its turn. Not an empty result; retry shortly. Other read paths are unaffected. |
503 | model_unavailable | A model a fact write needs gave no usable answer, or the service's daily model budget is spent (until 00:00 UTC, no Retry-After). Nothing is written; retry. POST and PATCH /v1/memories keep storing memories, and their facts are extracted after the pause. |
Rate limits & quotas
Two limits, two meanings. A short-term rate limit (requests
per minute, hour and day) returns 429 rate_limit_exceeded with a
Retry-After header, back off and retry. A request the rate limit refuses does not count against it, and what you do signed in to the dashboard has a limit of its own, with the same ceilings, so it does not eat into your keys'. A monthly
quota (memories written and queries per month, by tier)
returns 429 quota_exceeded with no Retry-After and a detail that says limit,
used and resets_at: a quota.warning webhook fires when the month's writes cross 80%, and
past a +10% soft cap you get a clean error rather than a surprise invoice. An
edit (PATCH of a memory or a fact) extracts again and counts like a
write: a memory one write per 6,000 characters of its text, as an add, a fact
one write. A batch whose memories do not fit in the writes left this month, the
batches already queued included, is refused before anything is stored. Reads are far more generous
than writes, because reads are retrieval, not generation. See
pricing for the per-tier numbers: monthly
quotas and requests per minute, hour and day (Hobby:
60 per minute, 1,000 per hour,
10,000 per day). A
429 rate_limit_exceeded carries Retry-After (seconds
until the window that refused resets) and a message naming that window's
limit. No other response carries rate-limit headers.
GET /v1/ping counts against the rate limit like every other call.
POST /v1/agents/init takes no key and has its own limit on new
accounts per network and per day (429 signup_rate_limited).
The endpoints
Grouped in the sidebar: Core memory operations (add, search,
list, get, update, delete, history), Context & facts
(the typed bi-temporal layer: get context, get, write, close and correct
facts, get profile), Users & agents (list and forget
users, declare a user's name, list and delete agents, the audit log, delete the account), and
Batch & status (batch import and status, write events,
ping). Signing up (POST /v1/agents/init) is on
Sign up as an agent. Start with
Add a memory.