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.
/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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
user_id | string | Required | None | The end user to build the profile for. Length 1-255 characters. |
agent_id | string | Optional | None | Filter to one agent namespace. |
as_of | string | Optional | None | ISO 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
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}| Field | Type | Description |
|---|---|---|
user_id | string | Echo of the end user the profile was built for. |
as_of | string · null | Echo of the as_of query string, raw and un-normalized, or null if you didn't send one. |
facts | array<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[].id | string | The fact id, e.g. fct_a1. |
facts[].subject | string | The subject of the triple. |
facts[].subject_type | string | From 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[].predicate | string | The normalized predicate, e.g. lives_in. |
facts[].predicate_raw | string | The predicate as it appeared in the source text, e.g. lives in. |
facts[].object | string | The object of the triple. |
facts[].object_is_literal | boolean | true when the object is a literal value rather than an entity. |
facts[].predicate_family | string | The family the predicate belongs to, e.g. places. |
facts[].confidence | number · null | Extraction confidence, 0-1. |
facts[].user_id / facts[].agent_id | string · null | The scope the fact belongs to (null if unscoped). |
facts[].valid_from | string · null | ISO 8601, when the fact became true (bi-temporal valid time). |
facts[].invalid_at | string · null | ISO 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_by | string · null | The id of the fact that superseded this one, or null. |
facts[].source_memory_id | string · null | The memory this fact was first extracted from; null for a fact written with POST /v1/facts. |
facts[].created_at | string · null | ISO 8601, when the store learned the fact. |
facts[].subject_canonical / facts[].object_canonical | string | The subject's and the object's current names after aliases. |
facts[].tense | string | current, past or planned. |
facts[].last_confirmed_at | string · null | ISO 8601, when a memory last restated the fact. |
facts[].observation_count | integer | How many memories assert the fact. |
facts[].source_memory_ids | array<string> | Every mem_ id that asserts the fact. |
by_family | object<string, array<object>> | The same facts grouped by predicate_family. The key is other when a fact's family is null. |
total | integer | Total active facts for this end user. May exceed the number returned in facts because the profile is capped, see truncated. |
truncated | boolean | true when total exceeds the number of returned facts, i.e. the 200-fact profile cap was hit. |
Errors
| Status | Code | Cause |
|---|---|---|
401 | invalid_key | Missing or invalid Authorization header. Message: Invalid or missing API key: ..., then what is wrong; response carries WWW-Authenticate: Bearer. |
403 | forbidden | The API key lacks the memories:read scope. Message: API key missing required scope(s): memories:read. |
422 | invalid_request | user_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. |
429 | rate_limit_exceeded | Per-tier minute / hour / day request limit exceeded. Message: Rate limit exceeded (...). Retry shortly.; response carries Retry-After and X-RateLimit-* headers. |
429 | quota_exceeded | Monthly 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_idis 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,
truncatedistrueandtotalreports the real count. For larger pulls use Get facts withlimit/offset. - Self-owned first. Facts the end user owns are sorted to the front, those whose
subject_typeisself, or whose subject equals theuser_id(case-insensitive, trimmed). Within each bucket the order of the query is kept: most recently confirmed first (last_confirmed_at, elsevalid_from), orvalid_fromdescending withas_of. - Grouped for you.
by_familybuckets the same facts bypredicate_family, falling back to the keyotherwhen a fact's family isnull. - True facts only. Only the facts true now (or at
as_of) are returned, there is noinclude_invalidatedoption on this endpoint. - Echoed as_of. The
as_ofin 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_oftime travel. - Get context, the assembled recall block, facts and memories in one call.
- SDK reference, the
get_profilemethod and its arguments.