Korely

Core memory operations

Add a memory

Store a memory. Korely extracts typed facts and resolves contradictions server-side; you just send the text and a scope.

POST /v1/memories

SDK: korely.add(content, ...). The write path runs the intelligence, embeddings, entity and typed-fact extraction, contradiction checking with bi-temporal validity, server-side. You never write supersede logic.

Authentication

HTTP header, required: Authorization: Bearer kor_live_.... The key must carry the memories:write scope.

Request body

FieldTypeRequiredDescription
contentstringRequiredThe memory text. 1-16,000 characters; leading and trailing whitespace is removed, and a blank text is refused.
user_idstringOptionalThe end user this memory belongs to. 1 to 255 characters, no /, no control characters, not . or .., not starting with erased:. Omit it for the shared namespace; an empty string is refused.
agent_idstringOptionalYour application's namespace. Same rule as user_id. Omit it for the default namespace, which never counts toward your agent cap.
run_idstringOptionalOne session or conversation. 1 to 255 characters; an empty string is refused, omit the field instead.
metadataobjectOptionalArbitrary JSON stored alongside the memory and echoed back on reads. At most 8,192 bytes once serialized, with finite numbers only: NaN and Infinity are refused.
timestampstringOptionalISO 8601 date or datetime of the event (a date is midnight UTC, no offset means UTC, omitted or blank means now). Sets the bi-temporal valid_from on facts extracted from this memory, use it when backfilling historical memories so the timeline stays correct. A timestamp later than now is read as now: for a fact that begins later, write it with POST /v1/facts and its own valid_from.
kindstringOptionalWhat the text is. note, the default: what somebody said or decided. session: the log of a work session, such as what a coding assistant's hooks save. A read can leave the sessions out, their facts with them, with exclude_sessions (see Work sessions).

Any other field is refused with 422 invalid_request (for example userId: Extra inputs are not permitted): field names are snake_case.

Example request

Terminal window
curl -X POST https://api.korely.ai/v1/memories \
-H "Authorization: Bearer kor_live_..." \
-H "Content-Type: application/json" \
-d '{
"content": "User prefers email follow-ups, not phone",
"user_id": "customer-giulia-4812",
"agent_id": "support-bot"
}'

Response

201 Created. The stored memory, with status processing and an empty facts list: the typed facts are derived a few seconds later (see the note below).

{
"id": "mem_8f2c1aab4d7e4f0c9a1b2c3d4e5f6a7b",
"content": "User prefers email follow-ups, not phone",
"user_id": "customer-giulia-4812",
"agent_id": "support-bot",
"run_id": null,
"client": null,
"kind": "note",
"metadata": {},
"status": "processing",
"created_at": "2026-06-17T10:22:00.412345+00:00",
"updated_at": null,
"facts": []
}
FieldTypeDescription
idstringThe memory id, e.g. mem_8f2c1aab4d7e4f0c9a1b2c3d4e5f6a7b.
contentstringThe text you stored, echoed back.
user_id / agent_id / run_idstring · nullThe scope you sent, echoed back (null if omitted).
clientstring · nullThe tool that wrote it, from the X-Korely-Client header (the SDKs send their own name). A label, not a namespace.
kindstringnote, or session for the log of a work session: the kind of the write.
metadataobjectThe metadata you sent ({} if omitted).
statusstringprocessing while the facts are being extracted, then ready (or error, see When extraction fails). Read it later with Get memory.
created_atstringISO 8601 timestamp of the write.
updated_atstring · nullnull until the memory is edited with Update a memory; then the ISO 8601 timestamp of the last edit.
factsarrayTyped (subject, predicate, object) facts extracted from this memory, when extraction ran inside the call. Each has id, subject, predicate, object, predicate_family (string · null), valid_from (string · null), invalidated (the fct_ ids it superseded), tense, invalid_at (string · null) and observation_count (above 1 when the write restated a fact the store already held). See the note on async extraction below.

Facts extract asynchronously. In production the add returns as soon as the memory is stored, with facts: [] (its vector is computed in the call, or by the worker shortly after when the embedder is busy); the extraction pipeline (entity + typed-fact extraction, contradiction checking) lands the facts a few seconds later. Read them back with Get facts or Get context on the next turn, don't block on them in the same request.

Work sessions

Terminal window
curl -X POST https://api.korely.ai/v1/memories \
-H "Authorization: Bearer kor_live_..." \
-H "Content-Type: application/json" \
-d '{
"content": "Session: moved the billing service to Postgres 16, tests pass, rollback script in ops/.",
"user_id": "dev-team",
"kind": "session"
}'

A memory with kind: "session" is stored, embedded and read into facts like any other. The difference is on the read side: pass exclude_sessions=true to Search memories, List memories, Get facts, Get profile or Get context, and the work sessions drop out, with the facts that only they state. A coding agent can keep its session logs in the same memory as the team's decisions, and a read that wants what was said and decided gets only that. The SDKs take kind from Python 0.1.26 and Node 0.1.16, and hand it back on every memory they return (Memory.kind) from Python 0.1.27 and Node 0.1.17.

Errors

StatusCodeCause
401invalid_keyMissing or invalid Authorization header.
403forbiddenThe key lacks the memories:write scope, or it is confined to some end users and the user_id is outside its list (or no user_id is given and the key does not name exactly one end user to default to).
413payload_too_largeThe body is larger than 2,097,152 bytes. Refused before it is read; nothing is written or counted. On the Cloud a body over 1 MB gets a bare 413 first, without this code.
422invalid_requestValidation failed: content missing, not a string, blank or over 16,000 chars; user_id or agent_id breaking the id rule; run_id empty or over 255; metadata over 8,192 bytes or holding NaN or Infinity; timestamp not ISO 8601; a kind other than note or session; malformed JSON; an unknown field.
429quota_exceededMonthly writes used up, 10% grace included; nothing is written. detail carries limit, used and resets_at (00:00 UTC on the 1st). No Retry-After: read resets_at, top up the month on a paid plan, or upgrade.
429agent_cap_exceededA new agent_id beyond your plan's agent cap. Nothing is written or counted: reuse one from List agents, delete one, or upgrade. detail carries limit and used.
429rate_limit_exceededPer-minute, per-hour or per-day request limit. Carries Retry-After.

Notes

  • One write per 6,000 characters. An add of up to 6,000 characters counts one write against your monthly write quota, however many facts it produces. A longer one counts one write per 6,000 characters, rounded up: 16,000 characters, the most a memory can hold, count 3. The engine may make more extraction calls than that (its windows overlap); you pay only the writes. A memory that does not fit in the writes left this month is refused whole with 429 quota_exceeded.
  • Contradictions are checked automatically. A model compares each new fact with the open facts it could conflict with and closes the ones the new fact replaces (a new address closes the old one; a second hobby does not). A closed fact is not deleted and stays readable with as_of.
  • Messages, too. The SDKs accept a list of chat messages as content and join them into one block before sending.

Related