Korely

Context & facts

Correct a fact

A correction writes a new fact and closes the old one. It is not an edit: the old row keeps its dates and gains a pointer to the new one, so as_of before the correction still returns what you believed then.

PATCH /v1/facts/{fact_id}

SDK: korely.correct_fact(fact_id, object=...). A store that edits a row in place cannot answer "what did we think in June", and answering that is the point of keeping history.

Authentication

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

Request body

At least one of the three. Anything you leave out is carried over from the fact you are correcting.

FieldTypeRequiredDescription
subjectstringOptionalCorrected subject. 1-200 characters.
predicatestringOptionalCorrected predicate; canonicalized server-side. 1-200 characters.
objectstringOptionalCorrected object. 1-500 characters.

Any other field is refused with 422 invalid_request.

Example request

Terminal window
curl -X PATCH https://api.korely.ai/v1/facts/fct_a1 \
-H "Authorization: Bearer kor_live_..." \
-H "Content-Type: application/json" \
-d '{"object": "Basic plan"}'

Response

200 OK. The new fact, with the id of the one it superseded.

{
"id": "fct_a2",
"subject": "customer-giulia-4812",
"predicate": "subscribes_to",
"object": "Basic plan",
"predicate_family": "ownership",
"valid_from": "2026-06-20T09:14:02+00:00",
"invalidated": ["fct_a1"],
"tense": "current",
"invalid_at": null,
"observation_count": 1,
"user_id": "customer-giulia-4812",
"agent_id": "support-bot"
}

The write shape of Write a fact: invalidated lists the corrected fact first, then any other fact the contradiction check closed.

Only a current fact is corrected

Correct the fact that holds now. A fact that is history (superseded by a newer one, forgotten, or ended) answers 409 fact_not_current. current_fact_id is the fact to correct instead, so a client retries on it without reading the message:

{
"detail": {"code": "fact_not_current", "message": "This fact is no longer current, so it cannot be corrected. It was superseded by fct_a2: correct that one instead.", "current_fact_id": "fct_a2"},
"code": "fact_not_current",
"message": "This fact is no longer current, so it cannot be corrected. It was superseded by fct_a2: correct that one instead.",
"current_fact_id": "fct_a2"
}

When no fact holds now, current_fact_id is null and the message says to write the value that holds now with POST /v1/facts. To change what was true in the past, write what happened with its dates there; a correction never closes the value in force because of an old row.

Errors

StatusCodeCause
401invalid_keyMissing or invalid kor_live_ key.
403forbiddenThe key lacks the memories:write scope.
404not_foundThe id is malformed, unknown, or the fact is in another project: No fact with that id. No write is counted. With the month's quota spent, a well-formed unknown id gets the 429 first.
409fact_not_currentThe fact is no longer current: superseded, forgotten or ended. current_fact_id is the current fact, null when there is none. Nothing is written and no write is counted (the reserved write is given back). With the month's quota spent, the 429 comes first.
413payload_too_largeThe body is larger than 2,097,152 bytes. Refused before it is read; nothing changes. On the Cloud a body over 1 MB gets a bare 413 first, without this code.
422invalid_requestThe body is empty or every field is blank (Give at least one of subject, predicate or object.), a field is over its length limit, or a field is unknown.
429quota_exceededMonthly writes used up, 10% grace included. Nothing changes. detail carries limit, used and resets_at.
429rate_limit_exceededPer-minute, per-hour or per-day request limit. Carries Retry-After.
503model_unavailableThe model that resolves the relation, or the contradiction check, gave no usable answer, or the service's daily model budget is spent (until 00:00 UTC). Nothing was written; retry.

Notes

  • An empty body is refused with 422. A body that restates the open fact as it is answers 200 with the same id and invalidated: [], and still uses one write.
  • It counts as one write. A correction uses one write of your monthly quota, like any PATCH; past the quota it answers 429 quota_exceeded and nothing changes. A 404 or a 409 costs nothing; with the month's quota spent, a 429 comes first.
  • Scoped to your key's project. A fact in another project answers 404, the same answer as an id that never existed.
  • Both stay readable. The old fact comes back with include_invalidated=true and in any as_of read before the correction.