The people your agents talk to and you generate on behalf of.
When and why to call these: the end users guide.
List end users
Section titled “List end users”GET /v1/end-users
Newest first.
End users once minted for a session are hidden unless you ask for them with include_generated=true: a conversation opened without an end_user_id used to create one. None is minted any more - a conversation needs a key, and a key its end user.
curl "https://api.lumavox.ai/v1/end-users" \ -H "Authorization: Bearer $API_KEY"Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
include_generated | boolean | Also list the end users once minted for a session opened without one. Default false. | |
limit | integer | How many to answer, 1 to 200. 1–200. Default 50. | |
cursor | string | The next_cursor of the page before. At least 1 characters. |
Responses
| Status | Description |
|---|---|
200 |
application/json — One page of end users, newest first |
401 |
Missing or invalid credentials |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
data |
array of EndUserInfo | |
data[].created_at |
string (date-time) | |
data[].display_name |
string or null | The name you gave them, or null. |
data[].external_id |
string or null | Your own id for this person, if you gave one. Null otherwise — every generated end user has none. |
data[].facts_updated_at |
string (date-time) or null | When something was last learned or forgotten about this person. Null means nothing has ever been stored about them. |
data[].id |
string | The end user’s identifier. Send it as end_user_id when opening a session, and keep it — it is how this person is recognised again, and what their long-term memory is filed under. |
data[].origin |
"created", "generated" |
created when you made this end user deliberately, generated when a session was opened without an id and one was minted for it. |
data[].sessions |
integer | How many conversations this person has had. |
next_cursor |
string or null | Pass as cursor for the next page; null when this is the last. |
Create an end user
Section titled “Create an end user”POST /v1/end-users
Somebody your agents will talk to.
Send your own external_id and this is idempotent — the same value always returns the same person, created only the first time. That is the recommended way to use it: pass your user id at every sign-in and you never have to store the eu_... we mint, while their memory and every relationship stay attached.
Send no external_id and you get a fresh person each call, and must keep the returned id — it is the only way back to what is remembered about them.
Make the person before their key: an ephemeral key is minted for one end user, and a conversation is opened with a key.
Your plan caps how many end users you hold: past it, a new one is a 409 naming the limit, while a repeat of an existing external_id is answered as ever.
A repeat call answers 200 rather than 201, so the two cases are distinguishable without comparing ids.
curl -X POST "https://api.lumavox.ai/v1/end-users" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{}'Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
display_name | string or null | A human name, for your dashboard and for reading a transcript. Nothing resolves by it — names are not unique — and it is never shown to the agent unless you put it in the conversation yourself. Optional, and worth leaving empty if you would rather not store a name here: eu_... is not personal data and a name is. At most 128 characters. | |
external_id | string or null | Your own id for this person — whatever you already call them. Optional, and unique within your organisation. Sending it makes this call idempotent: the same value always returns the same end user, creating one only the first time. That means you never have to store the id we mint — pass yours at every sign-in and the person is recognised, with their whole memory and every relationship intact. It can be used anywhere an end_user_id is accepted, interchangeably with the eu_... form. At most 128 characters. |
Responses
| Status | Description |
|---|---|
200 |
application/json — The end user this external_id already named |
201 |
application/json — The end user. The same external_id always returns the same one |
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 — a key limited to tts gets this from /v1/images rather than a 401 |
409 |
The organisation already holds as many end users as its plan allows. Delete one, or move to a larger plan. |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
created_at |
string (date-time) | |
display_name |
string or null | The name you gave them, or null. |
external_id |
string or null | Your own id for this person, if you gave one. Null otherwise — every generated end user has none. |
facts_updated_at |
string (date-time) or null | When something was last learned or forgotten about this person. Null means nothing has ever been stored about them. |
id |
string | The end user’s identifier. Send it as end_user_id when opening a session, and keep it — it is how this person is recognised again, and what their long-term memory is filed under. |
origin |
"created", "generated" |
created when you made this end user deliberately, generated when a session was opened without an id and one was minted for it. |
sessions |
integer | How many conversations this person has had. |
Read an end user
Section titled “Read an end user”GET /v1/end-users/{end_user_id}
end_user_id may be the eu_... we minted or your own external_id — the two are interchangeable everywhere one is accepted.
curl "https://api.lumavox.ai/v1/end-users/$END_USER_ID" \ -H "Authorization: Bearer $API_KEY"Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required |
Responses
| Status | Description |
|---|---|
200 |
application/json — The end user |
401 |
Missing or invalid credentials |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
created_at |
string (date-time) | |
display_name |
string or null | The name you gave them, or null. |
external_id |
string or null | Your own id for this person, if you gave one. Null otherwise — every generated end user has none. |
facts_updated_at |
string (date-time) or null | When something was last learned or forgotten about this person. Null means nothing has ever been stored about them. |
id |
string | The end user’s identifier. Send it as end_user_id when opening a session, and keep it — it is how this person is recognised again, and what their long-term memory is filed under. |
origin |
"created", "generated" |
created when you made this end user deliberately, generated when a session was opened without an id and one was minted for it. |
sessions |
integer | How many conversations this person has had. |
Rename an end user, or change your id for them
Section titled “Rename an end user, or change your id for them”PATCH /v1/end-users/{end_user_id}
Absent fields are untouched; null clears one.
There is no field for the eu_... id. Long-term memory is filed under it, so rewriting it would strand everything remembered about this person. Your external_id is the identifier you can change.
curl -X PATCH "https://api.lumavox.ai/v1/end-users/$END_USER_ID" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{}'Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
display_name | string or null | A human name, for your dashboard and for reading a transcript. Nothing resolves by it — names are not unique — and it is never shown to the agent unless you put it in the conversation yourself. Optional, and worth leaving empty if you would rather not store a name here: eu_... is not personal data and a name is. At most 128 characters. | |
external_id | string or null | Your own id for this person — whatever you already call them. Optional, and unique within your organisation. Sending it makes this call idempotent: the same value always returns the same end user, creating one only the first time. That means you never have to store the id we mint — pass yours at every sign-in and the person is recognised, with their whole memory and every relationship intact. It can be used anywhere an end_user_id is accepted, interchangeably with the eu_... form. At most 128 characters. |
Responses
| Status | Description |
|---|---|
200 |
application/json — The updated end user |
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 — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id |
409 |
Another end user in this organisation already has that external_id. |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
created_at |
string (date-time) | |
display_name |
string or null | The name you gave them, or null. |
external_id |
string or null | Your own id for this person, if you gave one. Null otherwise — every generated end user has none. |
facts_updated_at |
string (date-time) or null | When something was last learned or forgotten about this person. Null means nothing has ever been stored about them. |
id |
string | The end user’s identifier. Send it as end_user_id when opening a session, and keep it — it is how this person is recognised again, and what their long-term memory is filed under. |
origin |
"created", "generated" |
created when you made this end user deliberately, generated when a session was opened without an id and one was minted for it. |
sessions |
integer | How many conversations this person has had. |
Delete an end user and everything about them
Section titled “Delete an end user and everything about them”DELETE /v1/end-users/{end_user_id}
Removes the end user, every conversation they have had, and everything remembered about them. Cannot be undone.
This is what to call when one of your users asks to be forgotten. DELETE /v1/agent/facts erases only the memory and leaves the conversations; this erases both.
The id is not reissued, and nothing that was filed under it is reachable again.
curl -X DELETE "https://api.lumavox.ai/v1/end-users/$END_USER_ID" \ -H "Authorization: Bearer $API_KEY"Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required |
Responses
| Status | Description |
|---|---|
200 |
application/json — The end user and every conversation with them are gone, counted |
401 |
Missing or invalid credentials |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id |
422 |
The request failed validation |
429 |
Rate limit exceeded |
200 response body
| Field | Type | Description |
|---|---|---|
id |
string | The end user that was deleted. |
facts_deleted |
integer | Durable facts erased with this person — all of them. |
sessions_deleted |
integer | Conversations this person had, all of them removed. |
What is remembered about an end user
Section titled “What is remembered about an end user”GET /v1/end-users/{end_user_id}/facts
The person’s facts, oldest first, a page at a time — what GET /v1/agent/facts answers their own key, here for your server with no key to mint. include_replaced=true lists those a later conversation replaced or removed too, until they are deleted.
curl "https://api.lumavox.ai/v1/end-users/$END_USER_ID/facts" \ -H "Authorization: Bearer $API_KEY"Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required |
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
include_replaced | boolean | Also 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. | |
limit | integer | How many to answer, 1 to 200. 1–200. Default 100. | |
cursor | string | The next_cursor of the page before. At least 1 characters. |
Responses
| Status | Description |
|---|---|
200 |
application/json — One page of what is remembered, oldest first |
401 |
Missing or invalid credentials |
403 |
The key is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id |
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. |
Tell the agents something about an end user
Section titled “Tell the agents something about an end user”POST /v1/end-users/{end_user_id}/facts
Adds a fact about the person, as you state it, for the agents to know from their next turn — what your records already hold: a name, a plan, a preference. It works before they have ever talked to an agent.
It is yours (source customer): a later conversation confirms it but never replaces or removes it. With agent_id only that agent recalls it. Idempotent by its words: a fact already saying it is answered 200, now yours, and a new one 201. Free.
curl -X POST "https://api.lumavox.ai/v1/end-users/$END_USER_ID/facts" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"text":"Prefers to be called Sam."}'Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Required | What 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_id | string or null | Keep 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 is valid but its scopes do not cover this capability — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id |
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. |
Correct what is remembered about an end user
Section titled “Correct what is remembered about an end user”PATCH /v1/end-users/{end_user_id}/facts/{fact_id}
Rewrites one fact. 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 already replaced, or words another fact already says, are a 409. Free.
curl -X PATCH "https://api.lumavox.ai/v1/end-users/$END_USER_ID/facts/$FACT_ID" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"text":"Prefers to be called Sam."}'Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required | |
fact_id | string | Required |
Request body (application/json)
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Required | What 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 — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id, or 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. |
Forget one fact about an end user
Section titled “Forget one fact about an end user”DELETE /v1/end-users/{end_user_id}/facts/{fact_id}
Deletes one fact; no reading of what was said before brings it back. Their conversations stay — DELETE /v1/end-users/{id} removes the person and everything about them. Cannot be undone.
curl -X DELETE "https://api.lumavox.ai/v1/end-users/$END_USER_ID/facts/$FACT_ID" \ -H "Authorization: Bearer $API_KEY"Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
end_user_id | string | Required | |
fact_id | string | Required |
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 — a key limited to tts gets this from /v1/images rather than a 401 |
404 |
Unknown end user id, or Unknown fact id |
422 |
The request failed validation |
429 |
Rate limit exceeded |