Korely

Context & facts

Get profile

Everything Korely currently knows about one end user, in a single call, their active typed facts, self-owned facts first, also grouped by predicate family. Deterministic, no model call.

GET /v1/profile

SDK: korely.get_profile(...). Where Get facts is a flat, filterable list across all your end users, a profile is always per end user: user_id is required. You get the active facts the user owns sorted first, plus a by_family grouping ready to render. It is a pure filter-and-sort, no embeddings, no LLM.

Authentication

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

Query parameters

user_id is required, a profile is built for exactly one end user. The rest are optional.

ParameterTypeRequiredDefaultDescription
user_idstringRequiredNoneThe end user to build the profile for. Length 1-255 characters.
agent_idstringOptionalNoneFilter to one agent namespace.
as_ofstringOptionalNoneISO date or datetime, return the profile as it was on that date. A bare date (2026-06-01) means midnight; naive values are coerced to UTC.

Example request

Terminal window
curl -G https://api.korely.ai/v1/profile \
-H "Authorization: Bearer kor_live_..." \
--data-urlencode "user_id=customer-giulia-4812"

Response

200 OK. The end user's facts true now (or at as_of), self-owned first, then the most recently confirmed first (last_confirmed_at, else valid_from, descending; with as_of, valid_from descending), plus the same facts grouped by predicate family.

{
"user_id": "customer-giulia-4812",
"as_of": null,
"facts": [
{
"id": "fct_a1",
"subject": "customer-giulia-4812",
"subject_type": "person",
"predicate": "lives_in",
"predicate_raw": "lives in",
"object": "Berlin",
"object_is_literal": true,
"predicate_family": "places",
"confidence": 0.95,
"user_id": "customer-giulia-4812",
"agent_id": "support-bot",
"valid_from": "2026-04-10T00:00:00+00:00",
"invalid_at": null,
"invalidated_by": null,
"source_memory_id": "mem_8f2c1a",
"created_at": "2026-04-10T08:00:00+00:00",
"subject_canonical": "customer-giulia-4812",
"object_canonical": "Berlin",
"tense": "current",
"last_confirmed_at": "2026-04-10T00:00:00+00:00",
"observation_count": 1,
"source_memory_ids": ["mem_8f2c1a"]
}
],
"by_family": {
"places": [
{
"id": "fct_a1",
"subject": "customer-giulia-4812",
"subject_type": "person",
"predicate": "lives_in",
"predicate_raw": "lives in",
"object": "Berlin",
"object_is_literal": true,
"predicate_family": "places",
"confidence": 0.95,
"user_id": "customer-giulia-4812",
"agent_id": "support-bot",
"valid_from": "2026-04-10T00:00:00+00:00",
"invalid_at": null,
"invalidated_by": null,
"source_memory_id": "mem_8f2c1a",
"created_at": "2026-04-10T08:00:00+00:00",
"subject_canonical": "customer-giulia-4812",
"object_canonical": "Berlin",
"tense": "current",
"last_confirmed_at": "2026-04-10T00:00:00+00:00",
"observation_count": 1,
"source_memory_ids": ["mem_8f2c1a"]
}
]
},
"total": 1,
"truncated": false
}
FieldTypeDescription
user_idstringEcho of the end user the profile was built for.
as_ofstring · nullEcho of the as_of query string, raw and un-normalized, or null if you didn't send one.
factsarray<object>A flat list of the serialized facts (same shape as Get facts), sorted self/own-subject first, then most recently confirmed first within each bucket.
facts[].idstringThe fact id, e.g. fct_a1.
facts[].subjectstringThe subject of the triple.
facts[].subject_typestringFrom extraction: person, organization, product, place, concept, event or unknown. On a fact written with POST /v1/facts, what the caller sent (for example self).
facts[].predicatestringThe normalized predicate, e.g. lives_in.
facts[].predicate_rawstringThe predicate as it appeared in the source text, e.g. lives in.
facts[].objectstringThe object of the triple.
facts[].object_is_literalbooleantrue when the object is a literal value rather than an entity.
facts[].predicate_familystringThe family the predicate belongs to, e.g. places.
facts[].confidencenumber · nullExtraction confidence, 0-1.
facts[].user_id / facts[].agent_idstring · nullThe scope the fact belongs to (null if unscoped).
facts[].valid_fromstring · nullISO 8601, when the fact became true (bi-temporal valid time).
facts[].invalid_atstring · nullISO 8601, when the fact stops being true, or null. Non-null only for a known future end date, or with as_of for a fact that ended after that date.
facts[].invalidated_bystring · nullThe id of the fact that superseded this one, or null.
facts[].source_memory_idstring · nullThe memory this fact was first extracted from; null for a fact written with POST /v1/facts.
facts[].created_atstring · nullISO 8601, when the store learned the fact.
facts[].subject_canonical / facts[].object_canonicalstringThe subject's and the object's current names after aliases.
facts[].tensestringcurrent, past or planned.
facts[].last_confirmed_atstring · nullISO 8601, when a memory last restated the fact.
facts[].observation_countintegerHow many memories assert the fact.
facts[].source_memory_idsarray<string>Every mem_ id that asserts the fact.
by_familyobject<string, array<object>>The same facts grouped by predicate_family. The key is other when a fact's family is null.
totalintegerTotal active facts for this end user. May exceed the number returned in facts because the profile is capped, see truncated.
truncatedbooleantrue when total exceeds the number of returned facts, i.e. the 200-fact profile cap was hit.

Errors

StatusCodeCause
401invalid_keyMissing or invalid Authorization header. Message: Invalid or missing API key: ..., then what is wrong; response carries WWW-Authenticate: Bearer.
403forbiddenThe API key lacks the memories:read scope. Message: API key missing required scope(s): memories:read.
422invalid_requestuser_id is missing or empty (it is required, length 1-255). A non-ISO as_of is also rejected here. Message: as_of must be an ISO date (2026-06-01) or datetime.
429rate_limit_exceededPer-tier minute / hour / day request limit exceeded. Message: Rate limit exceeded (...). Retry shortly.; response carries Retry-After and X-RateLimit-* headers.
429quota_exceededMonthly query quota (plus 10% grace) exhausted. The body adds limit (the plan's figure), used and resets_at (00:00 UTC on the 1st) to code and message ("Monthly query limit reached: ... queries on the ... plan, plus a 10% grace. It starts again on ..."). No Retry-After: read resets_at.

Notes

  • Deterministic. No model or LLM call, a pure filter and sort. The same request returns the same profile every time.
  • Per end user. user_id is required. That's the difference from the flat Get facts list, a profile is always built for one end user.
  • Capped at 200. The profile returns at most 200 facts. When the end user has more, truncated is true and total reports the real count. For larger pulls use Get facts with limit / offset.
  • Self-owned first. Facts the end user owns are sorted to the front, those whose subject_type is self, or whose subject equals the user_id (case-insensitive, trimmed). Within each bucket the order of the query is kept: most recently confirmed first (last_confirmed_at, else valid_from), or valid_from descending with as_of.
  • Grouped for you. by_family buckets the same facts by predicate_family, falling back to the key other when a fact's family is null.
  • True facts only. Only the facts true now (or at as_of) are returned, there is no include_invalidated option on this endpoint.
  • Echoed as_of. The as_of in the response echoes the raw query string; retrieval internally uses the normalized datetime.

Related

  • Get facts, the flat, filterable list of typed facts, with as_of time travel.
  • Get context, the assembled recall block, facts and memories in one call.
  • SDK reference, the get_profile method and its arguments.