Developer
API
Trulience API reference for token generation and avatar managementOverview
All endpoints use JSON. Authentication is via the x-api-key header.
Generate JWT Token
Generate a JWT token for avatar authentication.
Endpoint: POST https://trulience.com/auth/generate-token
Request Headers
x-api-key: tru_live_***
Content-Type: application/jsonRequest Body
{
"avatar_id": "4386676996480451678",
"expire_at": 300
}| Field | Type | Required | Description |
|---|---|---|---|
avatar_id | string | Yes | Avatar ID to generate token for |
expire_at | integer | No | Token expiry in seconds. Default: 120. Range: 60-3600 |
Success Response (200 OK)
{
"jwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 300,
"avatar_id": "4386676996480451678"
}| Field | Type | Description |
|---|---|---|
jwt | string | JWT token for avatar authentication |
expires_in | integer | Token expiry in seconds |
avatar_id | string | Avatar ID the token is valid for |
Error Responses
400 Bad Request - Invalid expire_at range
{
"error": {
"code": 19,
"message": "expire_at must be between 60 and 3600 seconds"
}
}401 Unauthorized - Invalid API Key
{
"error": {
"code": 16,
"message": "Invalid API Key"
}
}403 Forbidden - Missing Scope
{
"error": {
"code": 34,
"message": "API key lacks required scope"
}
}403 Forbidden - Avatar Not Allowed
{
"error": {
"code": 33,
"message": "API key is not authorized for this avatar"
}
}403 Forbidden - Origin Not Allowed
{
"error": {
"code": 35,
"message": "Origin is not allowed for this API key"
}
}429 Rate Limited
{
"error": {
"code": 36,
"message": "Too many requests. Please slow down."
}
}500 Internal Server Error
{
"error": {
"code": 45,
"message": "Internal server error occurred"
}
}Notes
- Tokens are single-use and cannot be refreshed
- Generate a new token for each user session
- Requires API key scope:
generate_tokens
List Avatars
Retrieve a paginated list of avatars for your account.
Endpoint: GET /avatars
Request Headers
x-api-key: tru_live_***Query Parameters
GET /avatars?page=0&size=20| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number (0-indexed). Default: 0 |
size | integer | No | Results per page. Default: 20. Max: 100 |
Success Response (200 OK)
{
"avatars": [
{
"id": "4386676996481151678",
"name": "Amanda"
},
{
"id": "993237220279768598",
"name": "Amanda - Trulience"
}
],
"pagination": {
"page": 0,
"size": 20,
"total": 82,
"total_pages": 5,
"has_next": true
}
}| Field | Type | Description |
|---|---|---|
avatars | array | Array of avatar objects |
avatars[].id | string | Avatar unique identifier |
avatars[].name | string | Avatar display name |
pagination.page | integer | Current page number (0-indexed) |
pagination.size | integer | Results per page |
pagination.total | integer | Total number of avatars |
pagination.total_pages | integer | Total number of pages |
pagination.has_next | boolean | Whether more pages are available |
Error Responses
401 Unauthorized - Invalid API Key
{
"error": {
"code": 16,
"message": "Invalid API Key"
}
}403 Forbidden - Missing Scope
{
"error": {
"code": 34,
"message": "API key lacks required scope"
}
}429 Rate Limited
{
"error": {
"code": 36,
"message": "Too many requests. Please slow down."
}
}500 Internal Server Error
{
"error": {
"code": 45,
"message": "Internal server error occurred"
}
}Notes
- Avatars are sorted alphabetically by name
- Requires API key scope:
read_avatars
Query Session State
Look up the current state of a live avatar session — avatar status, avatar ID, user ID, and last-activity time — by sessionId. Use this from your backend to poll session status without needing your own client-side event plumbing.
Endpoint: GET https://trulience.com/session/query
Creating a key with query permission
- Sign in to the Trulience Dashboard with an account that has access to your organization’s avatars
- Open Developer → API Keys
- Select Create New Key and give it a descriptive name (e.g. “Backend — session status polling”)
- Turn on the Read Session State permission. Keys without it are rejected by this endpoint
- Save, then copy the key immediately — it is shown only once and cannot be retrieved afterwards
- Store the key on your server only. Treat it like a password; never put it in client-side code
If the key is restricted to specific avatars (a per-avatar allowlist), it can only query sessions for those avatars — see error 33 below.
Request Headers
x-api-key: tru_live_***Query Parameters
GET /session/query?sessionId=sess_9f2a7c1e&fields=avatarStatus,avatarId,userId,lastActivityAt| Parameter | Type | Required | Description |
|---|---|---|---|
sessionId | string | Yes | The session to query. Max 128 characters. |
fields | string (comma-separated) | Yes | Which fields to return: one or more of avatarStatus, avatarId, userId, lastActivityAt. No default — there is no “return everything” shortcut, so name every field you need. |
Success Response (200 OK)
{
"status": "OK",
"failReason": 0,
"sessionId": "sess_9f2a7c1e",
"state": {
"avatarStatus": "TALKING",
"avatarId": 456,
"userId": 789,
"lastActivityAt": 1769784000123
}
}state contains only the fields you listed in fields — request a subset to get a smaller response. A field with no recorded value is still present, as null, rather than omitted.
| Field | Type | Description |
|---|---|---|
state.avatarStatus | string | null | One of IDLE, LOADED, UNLOADED, LISTENING, THINKING, TALKING |
state.avatarId | number | Avatar ID for this session |
state.userId | number | User ID for this session |
state.lastActivityAt | number | null | Epoch milliseconds of the most recent activity (ping or message). null if none has been recorded yet |
Failure Response
Failures use the same shape plus a message:
{
"status": "FAIL",
"failReason": 34,
"message": "API key lacks required scope"
}Querying a session that has already ended is not a failure on your part — it simply returns error 65 below.
Error Reference
| HTTP | Code | Message | What it means & what to do |
|---|---|---|---|
| 200 | 0 | OK | Success — no action needed |
| 401 | 30 | API key is required | Missing x-api-key header |
| 401 | 29 | Invalid API key format | Malformed key — check for copy/paste truncation |
| 401 | 31 | API key not found in database | Key doesn’t exist — confirm account/deletion |
| 401 | 16 | Invalid API Key | Key doesn’t validate — issue a new one if persistent |
| 403 | 32 | This API key has been disabled | Re-enable it or use a different key |
| 429 | 36 | Too many requests. Please slow down. | Back off and retry; avoid tight loops |
| 403 | 34 | API key lacks required scope | Enable “Read Session State” on the key |
| 400 | 7 | InvalidOrMissingParams | sessionId is missing/over 128 characters, or fields is missing/blank/contains an unrecognized name |
| 404 | 65 | Session not found | Already ended, or never existed — usually nothing to do |
| 403 | 24 | Avatar does not belong to your account | Session belongs to a different account |
| 403 | 33 | API key is not authorized for this avatar | Key’s avatar allowlist doesn’t include this one |
| 500 | 45 | Internal server error occurred | Retry; contact support if persistent |
Rate Limiting
This endpoint enforces rate limits at two layers, each with different numbers:
- Per API key — 100 requests burst, refilling at 50 requests/second by default. Shared with your key’s usage of the other endpoints on this page. Exceeding it returns the
429JSON shown above (failReason: 36). - Per source IP address, at the network edge — ~60 requests/second sustained, with a burst of 120. It’s set above the per-key ceiling so it won’t bind for legitimate traffic — the per-key limit above is the actual source of truth for your quota. Because this is rejected before the request reaches the application, the response is a bare HTTP
429without the usual{"status":"FAIL",...}JSON body — check the status code, not the response body, when handling throttling on this endpoint. This applies per source IP regardless of which key (or no key) is used, so if you send/session/querytraffic for many different API keys through one shared outbound IP (e.g. a corporate proxy or NAT), that IP is throttled as a whole.
No Retry-After header is returned by either layer — back off and retry (e.g. with exponential backoff) rather than retrying in a tight loop.
Need a higher per-key limit? Contact support.
Notes
- Requires API key permission: Read Session State
fieldsis required — any single unrecognized field name fails the whole request with a 400 rather than silently returning a truncated response- This is a point-in-time lookup, not a subscription — poll it if you need updates over time
Disconnect a Session
End an in-flight avatar session on demand by session_id. Use this to terminate sessions from your backend — for example, call moderation — in addition to the natural exit paths (client hangup, transport failure, max_session_duration).
Endpoint: POST https://trulience.com/sessions/disconnect
Creating a key with disconnect permission
- Sign in to the Trulience Dashboard with an account that has access to your organization’s avatars
- Open Developer → API Keys
- Select Create New Key and give it a descriptive name (e.g. “Backend — call moderation”)
- Turn on the Disconnect Sessions permission. Keys without it are rejected by this endpoint
- Save, then copy the key immediately — it is shown only once and cannot be retrieved afterwards
- Store the key on your server only. Treat it like a password; never put it in client-side code
If the key is restricted to specific avatars (a per-avatar allowlist), it can only disconnect sessions for those avatars — see error 33 below.
Request Headers
x-api-key: your-api-key
Content-Type: application/jsonRequest Body
{
"session_id": "sess_9f2a7c1e"
}| Field | Type | Required | Description |
|---|---|---|---|
session_id | string | Yes | The session to disconnect |
Success Response (200 OK)
{
"status": "OK",
"failReason": 0
}Failure Response
Failures use the same shape plus a message:
{
"status": "FAIL",
"failReason": 34,
"message": "API key lacks required scope"
}The call is safe to retry — disconnecting an already-ended session simply returns error 65, which is not a failure on your part.
Error Reference
| HTTP | Code | Message | What it means & what to do |
|---|---|---|---|
| 200 | 0 | OK | Success — no action needed |
| 401 | 30 | API key is required | Missing x-api-key header |
| 401 | 29 | Invalid API key format | Malformed key — check for copy/paste truncation |
| 401 | 31 | API key not found in database | Key doesn’t exist — confirm account/deletion |
| 401 | 16 | Invalid API Key | Key doesn’t validate — issue a new one if persistent |
| 403 | 32 | This API key has been disabled | Re-enable it or use a different key |
| 429 | 36 | Too many requests. Please slow down. | Back off and retry; avoid tight loops |
| 403 | 34 | API key lacks required scope | Enable “Disconnect Sessions” on the key |
| 400 | 7 | InvalidOrMissingParams | Missing session_id in the body |
| 404 | 65 | Session not found | Already ended — usually nothing to do |
| 403 | 24 | Avatar does not belong to your account | Session belongs to a different account |
| 403 | 33 | API key is not authorized for this avatar | Key’s avatar allowlist doesn’t include this one |
| 500 | 45 | Internal server error occurred | Retry; contact support if persistent |
Notes
- Requires API key permission: Disconnect Sessions
- Safe to call more than once — an already-ended session returns error
65