Chat Endpoints
SDK endpoints for NPC conversations. All requests require the X-API-Key header.
X-API-Key header. You can only access your own published personas.List Personas
GET /api/v1/sdk/personas
Returns all published personas owned by your API key. Use this to discover persona IDs for chat endpoints.
Response
Returns an array of persona objects:
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Persona ID to use in chat endpoints |
name | string | Persona display name |
description | string | null | Persona description |
created_at | string (ISO 8601) | When the persona was created |
updated_at | string (ISO 8601) | When the persona was last updated |
curl /api/v1/sdk/personas \
-H "X-API-Key: pk_live_..."Response:
[
{
"id": "a1b2c3d4-...",
"name": "Grumpy Barista",
"description": "A coffee shop NPC with a bad attitude",
"created_at": "2026-03-10T12:00:00Z",
"updated_at": "2026-03-10T12:00:00Z"
}
]Initialize Session
POST /api/v1/sdk/chat/{persona_id}/init-session
Starts a new chat session. Returns the NPC's opening greeting, session ID, and persona metadata.
user_session_id will reset the previous session. Use the Check Session endpoint first if you want to resume an existing conversation.Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
machine_id | string (UUID) | No | Target a specific state machine. Defaults to the persona's default machine. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
user_session_id | string | Yes | Your unique identifier for this player (e.g. player UUID from your game) |
player_name | string | Yes | Player's display name, used in NPC responses |
player_gender | string | Yes | One of female, male, or non-binary |
Response
| Field | Type | Description |
|---|---|---|
session_id | string (UUID) | Server-assigned internal session UUID |
user_session_id | string | Your player identifier (echoed back) |
persona_name | string | The NPC's display name |
persona_description | string | null | The NPC's description |
player_name | string | Echoed player name |
player_gender | string | Echoed player gender |
message | string | The NPC's opening greeting |
machine_id | string (UUID) | The active state machine ID |
Send Message
POST /api/v1/sdk/chat/{persona_id}/message
Sends a player message and returns the NPC response with state machine metadata.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The player's message text |
user_session_id | string | Yes | The user_session_id you provided during init |
Response
| Field | Type | Description |
|---|---|---|
message | string | The NPC's response |
current_state | string | Current state machine state key |
score | number | Cumulative session score |
outcome | string | null | Terminal outcome if reached (ACCEPT, REJECT, KICK_OUT) |
decision | string | null | AI's evaluation decision (pass, redirect, reject, kick_out) |
follow_up | boolean | Whether the NPC expects a follow-up |
redirect_count | number | null | Number of redirects used in the current state |
session_id | string (UUID) | Internal session identifier |
scoring_mode | string | Scoring mode (scoring or pass_fail) |
machine_completed | boolean | Whether the conversation reached a terminal state |
unlocked_machines | array | Newly unlocked machines (for multi-machine personas) |
Check Session
GET /api/v1/sdk/chat/{persona_id}/session
Check if a player already has an active session with a persona. Returns session status or 404 if no session exists. Useful for resuming conversations on reconnect instead of re-initializing.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_session_id | string | Yes | The player identifier to check |
machine_id | string (UUID) | No | Check a specific state machine |
Response
| Field | Type | Description |
|---|---|---|
session_id | string (UUID) | Internal session identifier |
persona_id | string (UUID) | Persona this session belongs to |
machine_id | string (UUID) | Active state machine |
current_state | string | Current state key in the state machine |
score | number | Current session score |
outcome | string | null | Terminal outcome if session is complete |
player_name | string | null | Player name set during init |
started_at | string (ISO 8601) | When the session started |
last_message_at | string (ISO 8601) | When the last message was sent |
List Available Machines
GET /api/v1/sdk/chat/{persona_id}/machines
Lists all machines (scenarios) available to a player for a persona. Includes entry machines, unlocked machines, and unlinked standalone machines. Use this to discover which machines a player can interact with.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_session_id | string | Yes | The player identifier to check availability for |
Response
Returns an array of available machine objects:
| Field | Type | Description |
|---|---|---|
machine_id | string (UUID) | Machine ID to pass to chat endpoints |
machine_key | string | Human-readable machine identifier |
name | string | Machine display name |
description | string | null | Machine description |
has_session | boolean | Whether the player has an active session on this machine |
session_outcome | string | null | Outcome if the machine was completed (ACCEPT, REJECT, etc.) |
is_linked | boolean | Whether this machine is part of a progression chain (has links to/from other machines) |
curl "/api/v1/sdk/chat/{persona_id}/machines?user_session_id=player-001" \
-H "X-API-Key: pk_live_..."Response:
[
{
"machine_id": "a1b2c3d4-...",
"machine_key": "opening_scene",
"name": "Opening Scene",
"description": "The first encounter with the barista",
"has_session": true,
"session_outcome": null,
"is_linked": true
},
{
"machine_id": "e5f6a7b8-...",
"machine_key": "side_quest",
"name": "Side Quest",
"description": "An optional standalone scenario",
"has_session": false,
"session_outcome": null,
"is_linked": false
}
]Get Chat History
GET /api/v1/sdk/chat/{persona_id}/history
Retrieves the full message history for a session.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_session_id | string | Yes | The session to retrieve history for |
machine_id | string (UUID) | No | Filter to a specific state machine |
Reset Session
POST /api/v1/sdk/chat/{persona_id}/reset
Resets a chat session, clearing all history and returning the state machine to its initial state.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_session_id | string | Yes | The session to reset |
machine_id | string (UUID) | No | Reset only a specific state machine |
Error Responses
All errors return a consistent JSON format:
{
"error": {
"message": "Description of what went wrong"
}
}| Status | Meaning |
|---|---|
| 400 | Invalid ID format or request body |
| 401 | Missing or invalid API key |
| 403 | API key doesn't own the persona, or persona is unpublished |
| 404 | Persona, session, or machine not found |
| 429 | Rate limited (30/min for messages, 60/min for other endpoints) |
Example: Full Conversation Flow
1. Discover your personas
curl /api/v1/sdk/personas \
-H "X-API-Key: pk_live_..."2. Check for existing session
curl "/api/v1/sdk/chat/{persona_id}/session?user_session_id=player-001" \
-H "X-API-Key: pk_live_..."
# Returns 404 if no session — proceed to init3. Initialize
curl -X POST /api/v1/sdk/chat/{persona_id}/init-session \
-H "X-API-Key: pk_live_..." \
-H "Content-Type: application/json" \
-d '{
"user_session_id": "player-001",
"player_name": "Alex",
"player_gender": "non-binary"
}'Response:
{
"session_id": "f7a8b9c0-...",
"user_session_id": "player-001",
"persona_name": "Grumpy Barista",
"persona_description": "A coffee shop NPC with a bad attitude",
"player_name": "Alex",
"player_gender": "non-binary",
"message": "Well, well... another traveler. What brings you here, Alex?",
"machine_id": "d4e5f6a7-..."
}4. Send a message
curl -X POST /api/v1/sdk/chat/{persona_id}/message \
-H "X-API-Key: pk_live_..." \
-H "Content-Type: application/json" \
-d '{
"message": "I heard you have something rare for sale.",
"user_session_id": "player-001"
}'Response:
{
"message": "Rare? Everything here is rare, friend. But the real question is — can you afford it?",
"current_state": "negotiation",
"score": 15,
"outcome": null,
"decision": "pass",
"follow_up": true,
"session_id": "f7a8b9c0-...",
"scoring_mode": "scoring",
"machine_completed": false,
"unlocked_machines": []
}5. Reset when done
curl -X POST "/api/v1/sdk/chat/{persona_id}/reset?user_session_id=player-001" \
-H "X-API-Key: pk_live_..."