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:

{
"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. Answered before the quota: no write is counted.
409fact_not_currentThe fact is no longer current: superseded, forgotten or ended. current_fact_id is the current fact, null when there is none. Answered before the quota: nothing is written and no write is counted.
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. The body adds 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. Nothing was written; retry.
503writes_pausedThe service's daily model budget is spent. Nothing was written; retry after Retry-After (00:00 UTC).

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 comes before the quota and costs nothing.
  • 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.