Core operations
Update a memory
Replace a memory's content and re-extract its facts in one call.
When you send a PATCH request, Korely replaces the stored content,
then runs the full extraction pipeline on the new text: entity detection,
typed fact extraction, and the two-stage contradiction check. Facts produced
by the old content that conflict with what the new text says are automatically
invalidated and replaced by the incoming facts. Facts that are not contradicted
remain active. The response returns the memory with its current fact set so
you can confirm what changed without a second round-trip.
Call this whenever an agent learns that previously recorded information is wrong or outdated — for example, a customer corrects a preference mid-session, or a support case is re-categorised after triage. You do not need to delete the memory and re-add it: update it in place and Korely handles the contradiction resolution automatically.
flowchart LR
A([PATCH /v1/memories/mem_8f2c1a]) --> B[Replace content]
B --> C[Re-run extraction]
C --> D{Contradiction check}
D -->|supersedes old fact| E[Invalidate fct_b91e]
D -->|no conflict| F[Keep existing facts]
E --> G([200 OK — updated memory + new facts])
F --> G Request
Endpoint: PATCH /v1/memories/{id}. SDK: korely.update(memory_id, *, content, expected_updated_at=None).
| Param | Type | Notes |
|---|---|---|
id | string | Required. The memory ID in the URL path (e.g. mem_8f2c1a). |
content | string | Required. The new plain text or Markdown that fully replaces the existing content. Extraction runs on this text. |
expected_updated_at | ISO 8601 string | Optional. Optimistic concurrency guard. Pass the updated_at value you last read. If the memory has been updated since then, the server returns 409 Conflict and the write is rejected. Omit to skip the check. |
Example
from korely_memory import Korely
korely = Korely(api_key="kor_live_...", region="eu")
# Basic update — new content replaces the old one; facts are re-extracted.result = korely.update( "mem_8f2c1a", content="Northwind Hosting costs 55 euro per month after the storage add-on.",)print(result.facts)# [Fact(id="fct_c30a", subject="Northwind Hosting",# predicate="costs", object="55 euro per month",# invalidated=["fct_b91e"])]# Return values are dataclasses — use attribute access (result.facts,# result.facts[0].predicate), never result["facts"].
# With optimistic concurrency: pass the updated_at you last saw.# A 409 means someone else wrote to this memory since you read it.result = korely.update( "mem_8f2c1a", content="Northwind Hosting costs 55 euro per month after the storage add-on.", expected_updated_at="2026-06-07T09:14:00Z",)Response
{ "id": "mem_8f2c1a", "content": "Northwind Hosting costs 55 euro per month after the storage add-on.", "agent_id": "infra-bot", "user_id": "customer-4812", "metadata": { "source": "slack" }, "created_at": "2026-06-07T09:14:00Z", "updated_at": "2026-06-09T16:02:00Z", "facts": [ { "id": "fct_c30a", "subject": "Northwind Hosting", "predicate": "costs", "object": "55 euro per month", "predicate_family": "financial", "valid_from": "2026-06-09T16:02:00Z", "invalidated": ["fct_b91e"] } ]}
The invalidated array lists every fact ID that the new content
superseded. Those facts still exist in the store — they appear in
GET /v1/memories/mem_8f2c1a/history — but they no longer appear
in search results or context calls unless you pass include_invalidated=true.
If the content change produces no contradictions, invalidated is an
empty array and all previous facts remain active.
Response fields
| Field | Type | Meaning |
|---|---|---|
id | string | The memory's permanent identifier. Never changes across updates. |
content | string | The new content as stored after this write. |
agent_id | string or null | The agent namespace this memory belongs to. |
user_id | string or null | The end-user scope. Unchanged by an update. |
metadata | object | The metadata last written via add(). Not modified by update(). |
created_at | ISO 8601 string | Original creation timestamp. Never changes. |
updated_at | ISO 8601 string | Timestamp of this write. Use this as the next expected_updated_at if you plan to chain updates. |
facts | array | The full current fact set extracted from the new content. Each item includes id, subject, predicate, object, predicate_family, valid_from, and invalidated (the array of fact IDs this fact supersedes). |
facts[].invalidated | array of strings | IDs of facts from the previous version that this new fact supersedes. Empty when no contradiction was detected. |
Errors
| Status | Code string | Cause |
|---|---|---|
401 | invalid_key | The Authorization header is missing, malformed, or the key has been revoked. |
404 | not_found | No memory exists for the given id, or it was previously deleted. |
409 | stale_write | expected_updated_at was provided but does not match the server's current updated_at. Another write happened since you last read this memory. Fetch the latest version and retry. |
422 | invalid_request | Request body failed validation — most commonly content is missing or empty. The body is the flat {"code":"invalid_request","message":"content: Field required"} envelope. |
429 | quota_exceeded | Your plan's monthly write quota (including the 10 % grace allowance) has been reached. Body is {"code":"quota_exceeded","message":"..."}; the write-quota 429 carries no Retry-After header. Quota resets at the start of your next billing month. |
Notes
- Not idempotent. Each call to
PATCH /v1/memories/{id}re-runs extraction and updatesupdated_at. Sending the same content twice produces two entries in the memory's history and re-validates facts each time. Useexpected_updated_atto guard against unintended repeated writes in retry loops. - Scoping is inherited, not settable. The
user_id,agent_id, andrun_idset at creation cannot be changed by an update. If you need to move a memory to a different scope, delete it and add a new one. - Metadata is not updated here. The
metadatafield is write-once fromadd(). If you need to attach new metadata, delete and re-add the memory. - Write quota. Each update counts as one write against your monthly quota (hobby: 1 k, developer: 5 k, team: 20 k, scale: 75 k). There is a soft +10 % grace above the limit before writes return
429. Reads and searches are never blocked by write quota. - Fact history is preserved. Superseded facts are never hard-deleted. They remain visible in
GET /v1/memories/{id}/historyand in facts queries wheninclude_invalidated=trueis set. This lets you audit how knowledge evolved over time. - Contradiction detection is automatic. You do not need to locate and delete old facts manually. Pass the corrected content and the two-stage contradiction pipeline identifies and invalidates any conflicting facts within the same user scope.
Related
- Add a memory — write new content and run the full extraction pipeline from scratch.
- Delete a memory — soft-delete one memory and invalidate its derived facts.
- Search memories — retrieve the memories most relevant to a query before deciding whether to update.
- API reference — full endpoint contract including
GET /v1/memories/{id}/historyfor auditing past versions.