Skip to content
Console

API reference

Conversations

Copy page

Conversations with an agent. There is a streaming door too, on a WebSocket that OpenAPI cannot describe — see The WebSocket in the docs.

When and why to call these: the conversations guide.

Every operation here takes an end user’s ephemeral token, never an API key: an API key gets 403. Mint one with POST /v1/ephemeral-keys — see End users and their keys.

GET /v1/agent/sessions

Most recently used first, a page at a time. Messages are not included — read one session for its transcript.

The key’s own end user and nobody else, and only conversations with the agents the key may talk to.

curl
curl "https://api.lumavox.ai/v1/agent/sessions" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Query parameters

NameTypeRequiredDescription
limitintegerHow many to answer, 1 to 200. 1–200. Default 50.
cursorstringThe next_cursor of the page before. At least 1 characters.

Responses

Status Description
200 application/json — One page of conversations, most recent first
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
data array of SessionInfo
data[].agent_id string
data[].created_at string (date-time)
data[].end_user_id string Who this conversation is with. Send it again to open another conversation with the same person, carrying their memory.
data[].id string
data[].title string or null
data[].turn_seq integer
data[].updated_at string (date-time)
next_cursor string or null Pass as cursor for the next page; null when this is the last.

POST /v1/agent/sessions

Called with the end user’s ephemeral key — the conversation is always that person’s, and end_user_id, if sent, must name them.

It continues the person’s most recent conversation with this agent, if there is one young enough to continue — the platform’s agents.sessions.resume_max_age_days (GET /v1/platform/limits), unless the organisation sets its own. Send resume: false to always start a new one — that is what a “new chat” button should do. The response’s resumed says which happened, and a continued conversation arrives with its messages already populated and its turn_seq past zero.

Editing the agent reaches this conversation too, within about a minute, from its next turn onward.

This call makes no model call and no speech call, and a new conversation comes back with no messages — even for an agent that has a first_message. The opening line is the agent’s first turn on /v1/agent/stream, written when a client connects, and streamed and spoken a sentence at a time like every other reply. The socket also decides whether to greet, and ready.greeting says which.

curl
curl -X POST "https://api.lumavox.ai/v1/agent/sessions" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"agent_id":"..."}'

Request body (application/json)

FieldTypeRequiredDescription
agent_idstringRequiredWhich agent this conversation is with.
end_user_idstring or nullOptional, and only ever the key’s own end user — their id from POST /v1/end-users, or your own id for them. A conversation is always the person the ephemeral key was minted for: the key says who is talking, so this can only confirm it, and naming anybody else is a 403. What the agent remembers about them — durable facts and the standing relationship — is theirs, and carries into every conversation with any of your agents. Set once, when the session opens. It cannot change afterwards. At most 128 characters.
resumeboolean or nullWhether to continue this person’s most recent conversation with this agent instead of starting a new one. Unset is the useful default: it resumes when this person has a conversation with this agent young enough to continue — within the organisation’s resume_max_age_days, else the platform’s agents.sessions.resume_max_age_days (GET /v1/platform/limits) — and starts a new one otherwise. That matches what ‘open a conversation with this person’ usually means, and it stops an integration that opens a session per page load from scattering somebody’s history across a dozen fragments. false always starts a new conversation — this is what a ‘new chat’ button should send. true is the same as leaving it unset; it exists so the intent can be stated rather than implied. Nothing is lost by starting fresh: durable facts and the standing relationship belong to the person, not the conversation, and are carried into every new one. The response’s resumed says which happened.
titlestring or nullOptional label. At most 255 characters.

Responses

Status Description
201 application/json — The conversation — new or continued, per resumed
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key’s scopes do not cover agents, or it is for another agent or person
404 Unknown agent id
422 The request failed validation
429 Rate limit exceeded

201 response body

Field Type Description
agent_id string
created_at string (date-time)
end_user_id string Who this conversation is with. Send it again to open another conversation with the same person, carrying their memory.
id string
title string or null
turn_seq integer
updated_at string (date-time)
messages MessagePage
messages.data array of MessageInfo
messages.data[].content string
messages.data[].created_at string (date-time)
messages.data[].id string
messages.data[].knowledge MessageKnowledge or null On a reply: what the agent looked up in its knowledge for it — each lookup’s query, outcome and the entries it found, with their scores. Null when nothing was looked up.
messages.data[].mood string or null How the agent said it felt when it wrote this reply, when the agent reports moods. Null on user messages, on agents with emotion off, and on any reply where the model did not report a usable one.
messages.data[].mood_intensity number or null How strongly, 0 to 1. Null when the model gave a label without a number — the label is the half it gets right.
messages.data[].role "user", "assistant"
messages.data[].sources array of MessageSource On a reply: the web pages it read, with the agent’s url_context switch on. Empty when it read none, and on the person’s messages.
messages.data[].tool_calls array of MessageToolCall On a reply: the calls of your tools it made, in order, each with its arguments and what it answered. Empty when it called none, and on the person’s messages.
messages.next_cursor string or null Pass as cursor for the next page; null when this is the last.
relation RelationInfo or null How this agent stands with this person, as the conversation opens. Null when the agent has relation_enabled off, which is not the same as “they have no history”: the counters run for every pair regardless, and returning one for an agent that keeps none would show a relationship the model is not being told about. It belongs to the person, not the conversation, so it carries across every session with the same end_user_id. Here so that rendering it at conversation start needs no second call; GET /v1/agent/relations is still how you read it any other time, and the socket’s relation event is how you learn it moved mid-turn — which is rare, and is the only time it changes.
relation.agent_id string
relation.agent_name string or null The agent’s name, so a list of these is readable without resolving ids.
relation.conversations integer Separate sessions, ever. A stronger signal of familiarity than turns — twenty short visits is a longer acquaintance than one long conversation.
relation.disclosure number How much the agent has told them about itself, -1 to 1 — the asymmetric half of knowing each other, and the one nothing can count. Deliberately not part of tier: an agent can have opened up to somebody it has come to dislike, and folding this into affection would make that state unrepresentable.
relation.end_user_id string The person, as eu_....
relation.first_met_at string (date-time) or null
relation.last_seen_at string (date-time) or null
relation.note string or null One line the model wrote about them. Replaced, not appended — it is rendered into every future prompt for this pair, so it is bounded by design.
relation.recorded integer How many times the model has recorded a change. Zero on a long history means the tool is not being called, which is the first thing to check when a relationship is not moving.
relation.summary string The relationship as the model is told it — bands and counted phrases, never numbers. Empty string when there is nothing worth saying yet, in which case nothing about them is added to the prompt at all — which is a real state and not a missing value.
relation.tier "Despised", "Disliked", "Acquaintances", "Friends", "Good Friends" What the agent would call this relationship, and what it is actually told: Despised, Disliked, Acquaintances, Friends or Good Friends. Derived on every read from the axes below and never stored, so it cannot go stale. The rule is one sentence: warmth and trust set the direction, familiarity sets how far it can go — a first conversation caps at Acquaintances however well it went, and the ceiling rises as they talk. Dislike is not capped: an agent can take against somebody on one remark.
relation.trust number -1 to 1, on the same scale.
relation.turns integer Turns exchanged, ever. Counted, not judged.
relation.warmth number -1 to 1. Zero is indifference, which is where every relationship starts.
resumed boolean True when this is a conversation that already existed rather than a new one — see resume on the request. Worth branching on: a resumed session arrives with its messages already populated and its turn_seq past zero, so a client that assumed an empty transcript will render nothing until the next turn.

GET /v1/agent/sessions/{session_id}

The transcript, oldest first, exactly as stored — including every turn from before a compaction. Compaction shortens what the model is sent, never what you can read back.

The most recent limit messages, because what a client renders is the end of a conversation.

To read it all, page backwards: pass messages.next_cursor as cursor; it is null once you have reached the start.

Each message carries the mood the agent reported when it wrote it, if the agent reports moods.

curl
curl "https://api.lumavox.ai/v1/agent/sessions/$SESSION_ID" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Path parameters

NameTypeRequiredDescription
session_idstringRequired

Query parameters

NameTypeRequiredDescription
limitintegerHow many messages, counting back from the newest, 1 to 200. The page itself is oldest first. 1–200. Default 50.
cursorstringmessages.next_cursor of the page before, for the older messages. At least 1 characters.

Responses

Status Description
200 application/json — The conversation and one page of its messages
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
404 Unknown session id
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
agent_id string
created_at string (date-time)
end_user_id string Who this conversation is with. Send it again to open another conversation with the same person, carrying their memory.
id string
title string or null
turn_seq integer
updated_at string (date-time)
messages MessagePage
messages.data array of MessageInfo
messages.data[].content string
messages.data[].created_at string (date-time)
messages.data[].id string
messages.data[].knowledge MessageKnowledge or null On a reply: what the agent looked up in its knowledge for it — each lookup’s query, outcome and the entries it found, with their scores. Null when nothing was looked up.
messages.data[].mood string or null How the agent said it felt when it wrote this reply, when the agent reports moods. Null on user messages, on agents with emotion off, and on any reply where the model did not report a usable one.
messages.data[].mood_intensity number or null How strongly, 0 to 1. Null when the model gave a label without a number — the label is the half it gets right.
messages.data[].role "user", "assistant"
messages.data[].sources array of MessageSource On a reply: the web pages it read, with the agent’s url_context switch on. Empty when it read none, and on the person’s messages.
messages.data[].tool_calls array of MessageToolCall On a reply: the calls of your tools it made, in order, each with its arguments and what it answered. Empty when it called none, and on the person’s messages.
messages.next_cursor string or null Pass as cursor for the next page; null when this is the last.
relation RelationInfo or null How this agent stands with this person, as the conversation opens. Null when the agent has relation_enabled off, which is not the same as “they have no history”: the counters run for every pair regardless, and returning one for an agent that keeps none would show a relationship the model is not being told about. It belongs to the person, not the conversation, so it carries across every session with the same end_user_id. Here so that rendering it at conversation start needs no second call; GET /v1/agent/relations is still how you read it any other time, and the socket’s relation event is how you learn it moved mid-turn — which is rare, and is the only time it changes.
relation.agent_id string
relation.agent_name string or null The agent’s name, so a list of these is readable without resolving ids.
relation.conversations integer Separate sessions, ever. A stronger signal of familiarity than turns — twenty short visits is a longer acquaintance than one long conversation.
relation.disclosure number How much the agent has told them about itself, -1 to 1 — the asymmetric half of knowing each other, and the one nothing can count. Deliberately not part of tier: an agent can have opened up to somebody it has come to dislike, and folding this into affection would make that state unrepresentable.
relation.end_user_id string The person, as eu_....
relation.first_met_at string (date-time) or null
relation.last_seen_at string (date-time) or null
relation.note string or null One line the model wrote about them. Replaced, not appended — it is rendered into every future prompt for this pair, so it is bounded by design.
relation.recorded integer How many times the model has recorded a change. Zero on a long history means the tool is not being called, which is the first thing to check when a relationship is not moving.
relation.summary string The relationship as the model is told it — bands and counted phrases, never numbers. Empty string when there is nothing worth saying yet, in which case nothing about them is added to the prompt at all — which is a real state and not a missing value.
relation.tier "Despised", "Disliked", "Acquaintances", "Friends", "Good Friends" What the agent would call this relationship, and what it is actually told: Despised, Disliked, Acquaintances, Friends or Good Friends. Derived on every read from the axes below and never stored, so it cannot go stale. The rule is one sentence: warmth and trust set the direction, familiarity sets how far it can go — a first conversation caps at Acquaintances however well it went, and the ceiling rises as they talk. Dislike is not capped: an agent can take against somebody on one remark.
relation.trust number -1 to 1, on the same scale.
relation.turns integer Turns exchanged, ever. Counted, not judged.
relation.warmth number -1 to 1. Zero is indifference, which is where every relationship starts.
resumed boolean True when this is a conversation that already existed rather than a new one — see resume on the request. Worth branching on: a resumed session arrives with its messages already populated and its turn_seq past zero, so a client that assumed an empty transcript will render nothing until the next turn.

DELETE /v1/agent/sessions/{session_id}

Deletes every message in it too. This cannot be undone.

curl
curl -X DELETE "https://api.lumavox.ai/v1/agent/sessions/$SESSION_ID" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Path parameters

NameTypeRequiredDescription
session_idstringRequired

Responses

Status Description
204 The session and its messages are gone
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
404 Unknown session id
422 The request failed validation
429 Rate limit exceeded

POST /v1/agent/sessions/{session_id}/compact

Summarises everything said so far but the last few exchanges and starts the next turn from that summary, then those exchanges word for word, instead of the full history. How many messages stay is the platform’s agents.memory.compaction.keep_messages; a conversation no longer than that is summarised whole.

The transcript is not changed — GET /v1/agent/sessions/{id} still returns every message. What changes is only what the model is sent.

This is a model call, charged to the key. Agents can also do it automatically by setting a token threshold.

curl
curl -X POST "https://api.lumavox.ai/v1/agent/sessions/$SESSION_ID/compact" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

Path parameters

NameTypeRequiredDescription
session_idstringRequired

Request body (application/json)

FieldTypeRequiredDescription
extract_factsboolean or nullWhether to also extract durable facts about the end user, in the same model call. Unset uses the agent’s own setting.

Responses

Status Description
200 application/json — The summary that replaced the turns it covers
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
402 The key has spent its credit — mint another; nothing was charged
403 The key is valid but its scopes do not cover this capability
404 Unknown session id
409 Another compaction of this conversation finished first
422 Nothing new to compact since the last compaction, or the model’s summary was empty or no shorter than what it would replace; nothing was charged
429 Rate limit exceeded
502 The model provider failed or timed out
503 The model provider is not configured

200 response body

Field Type Description
after_seq integer The last message this summary covers. Anything after it — the last few exchanges, kept word for word, then whatever is said next — is still sent to the model verbatim.
facts_stored integer Durable facts written to long-term memory by this call. Zero when extraction was not asked for, or when there was nothing worth keeping.
input_tokens integer or null
model string or null What produced the summary.
output_tokens integer or null
session_id string
summary string What the next turn will start from.
trigger "manual", "automatic", "idle" manual (a client asked) or automatic (a turn reached the agent’s threshold, or a long compaction’s next pass). idle is no longer written: it marks compactions made when a quiet conversation’s facts were read, before facts were read on their own.

POST /v1/agent/sessions/{session_id}/extract

Compacts the conversation and extracts durable facts about the user into long-term memory, in one model call, charged to the key.

Identical to POST /sessions/{id}/compact with {"extract_facts": true} — it exists because remembering and shortening are different intentions even though they are one request.

curl
curl -X POST "https://api.lumavox.ai/v1/agent/sessions/$SESSION_ID/extract" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Path parameters

NameTypeRequiredDescription
session_idstringRequired

Responses

Status Description
200 application/json — The facts pulled out of the conversation and stored
401 Missing or invalid credentials
402 The key has spent its credit — mint another; nothing was charged
403 The key is valid but its scopes do not cover this capability
404 Unknown session id
409 Another compaction of this conversation finished first
422 Nothing new to compact since the last compaction, or the model’s summary was empty or no shorter than what it would replace; nothing was charged
429 Rate limit exceeded
502 The model provider failed or timed out
503 The model provider is not configured

200 response body

Field Type Description
after_seq integer The last message this summary covers. Anything after it — the last few exchanges, kept word for word, then whatever is said next — is still sent to the model verbatim.
facts_stored integer Durable facts written to long-term memory by this call. Zero when extraction was not asked for, or when there was nothing worth keeping.
input_tokens integer or null
model string or null What produced the summary.
output_tokens integer or null
session_id string
summary string What the next turn will start from.
trigger "manual", "automatic", "idle" manual (a client asked) or automatic (a turn reached the agent’s threshold, or a long compaction’s next pass). idle is no longer written: it marks compactions made when a quiet conversation’s facts were read, before facts were read on their own.

GET /v1/agent/facts

What is stored about the key’s end user, oldest first, a page at a time — up to 200 a page, 100 by default. A fact learnt while you page lands on the last page.

Facts are shared across every agent you run — the same person talking to a different character is still the same person. agent_id records which one was being talked to when a fact was learned.

A fact a later conversation changed or contradicted is replaced: hidden from the agents and from this list, and deleted the platform’s agents.memory.facts.replaced_kept_days later (GET /v1/platform/limits). include_replaced=true lists those too, each with replaced_at, and replaced_by naming the fact that took its place.

curl
curl "https://api.lumavox.ai/v1/agent/facts" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Query parameters

NameTypeRequiredDescription
end_user_idstringOptional, and only ever the key’s own end user — their eu_... id or your own id for them. Anybody else is a 403.
include_replacedbooleanAlso list the facts a later conversation replaced or removed, until they are deleted, the platform’s agents.memory.facts.replaced_kept_days later (GET /v1/platform/limits). Default false.
limitintegerHow many to answer, 1 to 200. 1–200. Default 100.
cursorstringThe next_cursor of the page before. At least 1 characters.

Responses

Status Description
200 application/json — What the platform remembers about this end user
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
data array of FactInfo
data[].agent_id string or null Which agent was being talked to when this was learned.
data[].confirmed_at string (date-time) or null When a conversation last said it again; null for never. The agents see the most recently confirmed first when not every fact fits.
data[].created_at string (date-time)
data[].id string
data[].replaced_at string (date-time) or null When a later conversation replaced or removed it; null while it stands. Listed only with include_replaced=true.
data[].replaced_by string or null The fact that replaced it — moved city, changed job — or null when it was removed with nothing in its place, or stands.
data[].scope "person", "agent" person: recalled by every agent of yours that shares its facts. agent: kept to one agent (agent_id), which alone recalls it — learnt by an agent whose facts_scope is agent, or added for that agent.
data[].source "conversation", "customer" conversation: a reading learnt it. customer: you added or corrected it — a later conversation never replaces or removes it.
data[].text string
data[].updated_at string (date-time) When it last changed: its replaced_at once replaced, else when you last corrected it, else its created_at.
next_cursor string or null Pass as cursor for the next page; null when this is the last.

POST /v1/agent/facts

Adds a fact about the key’s end user, as you state it, for the agents to know from their next turn: what your app already knows and wants them to keep — a name, a preference.

It is yours: a later conversation confirms it but never replaces or removes it, and its source is customer. With agent_id only that agent recalls it; without, every agent of yours does. Free.

Idempotent by its words: a fact that already says the same thing is answered 200 — now yours — and a new one 201. A fact forgotten before is remembered again.

curl
curl -X POST "https://api.lumavox.ai/v1/agent/facts" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"Prefers to be called Sam."}'

Request body (application/json)

FieldTypeRequiredDescription
textstringRequiredWhat to remember about the person, as one plain statement: “Prefers to be called Sam.” At most 500 characters. Never a secret — a password, a code, a card, account or identity number, or a key is refused, since facts are sent to the model on every turn. 1–500 characters.
agent_idstring or nullKeep it to one agent: only that agent recalls it. Unset or null: every agent of yours that shares its facts — and the ones that keep their own, too.

Responses

Status Description
200 application/json — The fact that already said it, now yours
201 application/json — The fact, remembered
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key’s scopes do not cover this, or it is pinned to agents and agent_id names another
422 No text, or text that looks like a secret — a password, a code, a card, account or identity number, or a key — which no fact may hold
429 Rate limit exceeded

200 response body

Field Type Description
agent_id string or null Which agent was being talked to when this was learned.
confirmed_at string (date-time) or null When a conversation last said it again; null for never. The agents see the most recently confirmed first when not every fact fits.
created_at string (date-time)
id string
replaced_at string (date-time) or null When a later conversation replaced or removed it; null while it stands. Listed only with include_replaced=true.
replaced_by string or null The fact that replaced it — moved city, changed job — or null when it was removed with nothing in its place, or stands.
scope "person", "agent" person: recalled by every agent of yours that shares its facts. agent: kept to one agent (agent_id), which alone recalls it — learnt by an agent whose facts_scope is agent, or added for that agent.
source "conversation", "customer" conversation: a reading learnt it. customer: you added or corrected it — a later conversation never replaces or removes it.
text string
updated_at string (date-time) When it last changed: its replaced_at once replaced, else when you last corrected it, else its created_at.

DELETE /v1/agent/facts

Deletes everything remembered about the key’s end user. Cannot be undone.

It leaves their conversations and the end user itself alone. DELETE /v1/end-users/{id} removes all three, and is what to call when one of your users asks to be forgotten outright.

curl
curl -X DELETE "https://api.lumavox.ai/v1/agent/facts" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Query parameters

NameTypeRequiredDescription
end_user_idstringOptional, and only ever the key’s own end user — their eu_... id or your own id for them. Anybody else is a 403.

Responses

Status Description
200 application/json — How many stored facts were deleted
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
facts_deleted integer How many stored facts were deleted.

PATCH /v1/agent/facts/{fact_id}

Rewrites one fact about the key’s end user. It becomes yours (source customer), so a later conversation never replaces it, and the old words are kept as forgotten: no reading of what was said before brings them back.

A fact a later conversation already replaced is a 409 — correct the one that replaced it — and so are words another fact already says. Free.

curl
curl -X PATCH "https://api.lumavox.ai/v1/agent/facts/$FACT_ID" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN" \
-H "Content-Type: application/json" \
-d '{"text":"Prefers to be called Sam."}'

Path parameters

NameTypeRequiredDescription
fact_idstringRequired

Request body (application/json)

FieldTypeRequiredDescription
textstringRequiredWhat to remember about the person, as one plain statement: “Prefers to be called Sam.” At most 500 characters. Never a secret — a password, a code, a card, account or identity number, or a key is refused, since facts are sent to the model on every turn. 1–500 characters.

Responses

Status Description
200 application/json — The fact, corrected
400 The request could not be read: malformed JSON
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
404 Unknown fact id
409 Replaced by a later conversation, or another fact already says that
422 No text, or text that looks like a secret — a password, a code, a card, account or identity number, or a key — which no fact may hold
429 Rate limit exceeded

200 response body

Field Type Description
agent_id string or null Which agent was being talked to when this was learned.
confirmed_at string (date-time) or null When a conversation last said it again; null for never. The agents see the most recently confirmed first when not every fact fits.
created_at string (date-time)
id string
replaced_at string (date-time) or null When a later conversation replaced or removed it; null while it stands. Listed only with include_replaced=true.
replaced_by string or null The fact that replaced it — moved city, changed job — or null when it was removed with nothing in its place, or stands.
scope "person", "agent" person: recalled by every agent of yours that shares its facts. agent: kept to one agent (agent_id), which alone recalls it — learnt by an agent whose facts_scope is agent, or added for that agent.
source "conversation", "customer" conversation: a reading learnt it. customer: you added or corrected it — a later conversation never replaces or removes it.
text string
updated_at string (date-time) When it last changed: its replaced_at once replaced, else when you last corrected it, else its created_at.

DELETE /v1/agent/facts/{fact_id}

Deletes a single memory of the key’s end user. Cannot be undone.

curl
curl -X DELETE "https://api.lumavox.ai/v1/agent/facts/$FACT_ID" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Path parameters

NameTypeRequiredDescription
fact_idstringRequired

Responses

Status Description
204 The fact is gone
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
404 Unknown fact id
422 The request failed validation
429 Rate limit exceeded

GET /v1/agent/relations

One row per agent the key’s end user has talked to that keeps a relationship, most recently active first — or, with agent_id, that agent’s row alone.

warmth and trust are moved by the agent itself when something in a conversation changes its view; turns and conversations are counted. summary is the sentence the model is actually given.

Per end user: each person’s relationships live with that person, so one call reads one person’s.

curl
curl "https://api.lumavox.ai/v1/agent/relations" \
-H "Authorization: Bearer $EPHEMERAL_TOKEN"

Query parameters

NameTypeRequiredDescription
agent_idstringOnly this agent’s relationship.
end_user_idstringOptional, and only ever the key’s own end user — their eu_... id or your own id for them. Anybody else is a 403.
limitintegerHow many to answer, 1 to 200. 1–200. Default 50.
cursorstringThe next_cursor of the page before. At least 1 characters.

Responses

Status Description
200 application/json — How each agent feels about the person, most recent first
401 Missing or invalid credentials
403 The key is valid but its scopes do not cover this capability
404 Unknown agent id
422 The request failed validation
429 Rate limit exceeded

200 response body

Field Type Description
data array of RelationInfo
data[].agent_id string
data[].agent_name string or null The agent’s name, so a list of these is readable without resolving ids.
data[].conversations integer Separate sessions, ever. A stronger signal of familiarity than turns — twenty short visits is a longer acquaintance than one long conversation.
data[].disclosure number How much the agent has told them about itself, -1 to 1 — the asymmetric half of knowing each other, and the one nothing can count. Deliberately not part of tier: an agent can have opened up to somebody it has come to dislike, and folding this into affection would make that state unrepresentable.
data[].end_user_id string The person, as eu_....
data[].first_met_at string (date-time) or null
data[].last_seen_at string (date-time) or null
data[].note string or null One line the model wrote about them. Replaced, not appended — it is rendered into every future prompt for this pair, so it is bounded by design.
data[].recorded integer How many times the model has recorded a change. Zero on a long history means the tool is not being called, which is the first thing to check when a relationship is not moving.
data[].summary string The relationship as the model is told it — bands and counted phrases, never numbers. Empty string when there is nothing worth saying yet, in which case nothing about them is added to the prompt at all — which is a real state and not a missing value.
data[].tier "Despised", "Disliked", "Acquaintances", "Friends", "Good Friends" What the agent would call this relationship, and what it is actually told: Despised, Disliked, Acquaintances, Friends or Good Friends. Derived on every read from the axes below and never stored, so it cannot go stale. The rule is one sentence: warmth and trust set the direction, familiarity sets how far it can go — a first conversation caps at Acquaintances however well it went, and the ceiling rises as they talk. Dislike is not capped: an agent can take against somebody on one remark.
data[].trust number -1 to 1, on the same scale.
data[].turns integer Turns exchanged, ever. Counted, not judged.
data[].warmth number -1 to 1. Zero is indifference, which is where every relationship starts.
next_cursor string or null Pass as cursor for the next page; null when this is the last.