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.
/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
| Field | Type | Required | Description |
|---|---|---|---|
content | string | Required | The memory text. 1-16,000 characters; leading and trailing whitespace is removed, and a blank text is refused. |
user_id | string | Optional | The end user this memory belongs to. 1 to 255 characters, no /, no control characters, not . or ... Omit it for the shared namespace; an empty string is refused. |
agent_id | string | Optional | Your application's namespace. Same rule as user_id. Omit it for the default namespace, which never counts toward your agent cap. |
run_id | string | Optional | One session or conversation. Max 255 chars. |
metadata | object | Optional | Arbitrary 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. |
timestamp | string | Optional | ISO 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. |
Any other field is refused with 422 invalid_request (for example userId: Extra inputs are not permitted): field names are snake_case.
Example request
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_8f2c1a", "content": "User prefers email follow-ups, not phone", "user_id": "customer-giulia-4812", "agent_id": "support-bot", "run_id": null, "metadata": {}, "status": "processing", "created_at": "2026-06-17T10:22:00.412345+00:00", "updated_at": null, "facts": []}| Field | Type | Description |
|---|---|---|
id | string | The memory id, e.g. mem_8f2c1a. |
content | string | The text you stored, echoed back. |
user_id / agent_id / run_id | string · null | The scope you sent, echoed back (null if omitted). |
metadata | object | The metadata you sent ({} if omitted). |
status | string | processing while the facts are being extracted, then ready (or error). Read it later with Get memory. |
created_at | string | ISO 8601 timestamp of the write. |
updated_at | string · null | null until the memory is edited with Update a memory; then the ISO 8601 timestamp of the last edit. |
facts | array | Typed (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 and embedded, with facts: []; 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.
Errors
| Status | Code | Cause |
|---|---|---|
401 | invalid_key | Missing or invalid Authorization header. |
403 | forbidden | The key lacks the memories:write scope. |
403 | agent_cap_exceeded | A new agent_id beyond your plan's agent cap. Nothing is written or counted: reuse one from List agents, or upgrade. |
422 | invalid_request | Validation failed: content missing, not a string, blank or over 16,000 chars; user_id or agent_id breaking the id rule; run_id over 255; metadata over 8,192 bytes or holding NaN or Infinity; timestamp not ISO 8601; malformed JSON; an unknown field. |
429 | quota_exceeded | Monthly writes used up, 10% grace included; nothing is written. The body adds limit, used and resets_at (00:00 UTC on the 1st) to code and message. No Retry-After: read resets_at, top up the month on a paid plan, or upgrade. |
429 | rate_limit_exceeded | Per-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, because the engine reads it in windows of that size, one model call each: 16,000 characters, the most a memory can hold, count 3. A memory that does not fit in the writes left this month is refused whole with
429 quota_exceeded. - Contradictions are automatic. If this memory conflicts with an earlier fact (same predicate, different object), the old fact is superseded, invalidated, not deleted, and stays queryable via
as_of. - Messages, too. The SDKs accept a list of chat messages as
contentand join them into one block before sending.
Related
- Add a memory, guide, the narrative walkthrough with context.
- Search memories, read them back.
- Get context, the assembled recall block.