Skip to main content

Conversations API

Read and manage conversations between your characters and players. Each unique player_id + character_id pair creates a persistent conversation with full memory.

Base path: /api/v1/characters/{character_id}/players

:::info character_id The character_id in the URL path is the id returned by the Characters API. :::

:::note Migrating from /api/agents The older /api/agents/{agent_id}/players... routes still work, but they are deprecated. Their responses carry Deprecation, Link and Sunset headers pointing at their replacement. See the Legacy migration guide for the full mapping and the wire differences. :::

Query parameter names on these routes are camelCase. Unknown query parameters are ignored, so a snake_case name such as sort_by silently has no effect.


Get Conversation Stats​

GET /api/v1/characters/{character_id}/players/stats

Returns aggregate statistics for all conversations with a character.

Response​

{
"totalConversations": 156,
"totalMessages": 4230,
"firstActivity": "2026-01-15T10:30:00",
"lastActivity": "2026-03-01T14:22:00"
}
FieldTypeDescription
totalConversationsintegerTotal number of player conversations
totalMessagesintegerTotal messages across all conversations
firstActivitystring | nullISO 8601 timestamp of earliest conversation
lastActivitystring | nullISO 8601 timestamp of most recent activity

Example​

curl https://api.estuary-ai.com/api/v1/characters/550e8400-e29b-41d4-a716-446655440000/players/stats \
-H "X-API-Key: est_your_api_key"

List Conversations​

GET /api/v1/characters/{character_id}/players

Returns a paginated list of player conversations for a character.

Query Parameters​

ParameterTypeDefaultDescription
limitinteger50Results per page (1-100)
offsetinteger0Number of results to skip (minimum 0)
sortBystring"last_activity"Sort field: "last_activity", "created_at", "message_count", "player_id"
sortOrderstring"desc""asc" or "desc"
playerSearchstringnoneCase-insensitive substring match on player_id (max 128 characters)
minMessagesintegernoneOnly include conversations with at least this many messages

The parameter names are camelCase; the sortBy values are snake_case, as shown.

Response​

{
"conversations": [
{
"id": "conv_abc123",
"characterId": "550e8400-e29b-41d4-a716-446655440000",
"playerId": "player_xyz",
"apiKeyId": "key_abc123",
"createdAt": "2026-01-20T09:00:00",
"lastActivity": "2026-03-01T14:22:00",
"messageCount": 42,
"lastMemoryExtractionAt": "2026-03-01T14:25:00"
}
],
"total": 156,
"limit": 50,
"offset": 0,
"sortBy": "last_activity",
"sortOrder": "desc"
}
FieldTypeDescription
idstringConversation ID
characterIdstringThe character in this conversation
playerIdstringThe player in this conversation
apiKeyIdstring | nullThe API key that created the conversation
createdAtstring | nullISO 8601 timestamp
lastActivitystring | nullISO 8601 timestamp of the most recent message
messageCountinteger | nullMessages in this conversation
lastMemoryExtractionAtstring | nullISO 8601 timestamp of the last memory extraction

Example​

curl "https://api.estuary-ai.com/api/v1/characters/550e8400-e29b-41d4-a716-446655440000/players?limit=10&sortBy=message_count&sortOrder=desc" \
-H "X-API-Key: est_your_api_key"
const characterId = "550e8400-e29b-41d4-a716-446655440000";
const res = await fetch(
`https://api.estuary-ai.com/api/v1/characters/${characterId}/players?limit=10&minMessages=5`,
{ headers: { "X-API-Key": "est_your_api_key" } }
);
const data = await res.json();
console.log(`${data.total} conversations found`);

Get a Conversation​

GET /api/v1/characters/{character_id}/players/{player_id}

Returns details for a specific player's conversation. Responds with 404 when this player has never spoken to this character.

Response​

{
"id": "conv_abc123",
"characterId": "550e8400-e29b-41d4-a716-446655440000",
"playerId": "player_xyz",
"apiKeyId": "key_abc123",
"createdAt": "2026-01-20T09:00:00",
"lastActivity": "2026-03-01T14:22:00",
"messageCount": 42,
"lastMemoryExtractionAt": "2026-03-01T14:25:00"
}

Example​

curl https://api.estuary-ai.com/api/v1/characters/550e8400-e29b-41d4-a716-446655440000/players/player_xyz \
-H "X-API-Key: est_your_api_key"

Get Messages​

GET /api/v1/characters/{character_id}/players/{player_id}/messages

Returns messages for a player conversation, ordered chronologically (newest page first, messages within each page in chronological order).

Query Parameters​

ParameterTypeDefaultDescription
limitinteger100Messages per page (1-200)
pageinteger1Page number (1-indexed, minimum 1)

Response​

{
"messages": [
{
"id": 1001,
"conversationId": "conv_abc123",
"role": "user",
"content": "Hey, remember what we talked about last time?",
"speaker": null,
"timestamp": "2026-03-01T14:20:00",
"imageUrl": null,
"imageDescription": null
},
{
"id": 1002,
"conversationId": "conv_abc123",
"role": "assistant",
"content": "Of course! You were telling me about your hiking trip to Rocky Mountain National Park.",
"speaker": null,
"timestamp": "2026-03-01T14:20:05",
"imageUrl": null,
"imageDescription": null
}
],
"pagination": {
"page": 1,
"limit": 100,
"total": 42,
"hasMore": false
}
}
FieldTypeDescription
idintegerMessage ID
conversationIdstringThe conversation this message belongs to
rolestring"user" or "assistant"
contentstringMessage text
speakerstring | nullDisplay name of the person speaking, for shared multi-person conversations
timestampstring | nullISO 8601 timestamp
imageUrlstring | nullImage the player sent with this message
imageDescriptionstring | nullWhat the character saw in that image

:::info A player with no history returns an empty page A player who has never spoken to this character gets a 200 with messages: [] and total: 0, not a 404. The conversation record is created when the player first connects, and your app may load history before that happens. :::

Example​

curl "https://api.estuary-ai.com/api/v1/characters/550e8400-e29b-41d4-a716-446655440000/players/player_xyz/messages?limit=50&page=1" \
-H "X-API-Key: est_your_api_key"

Delete a Conversation​

DELETE /api/v1/characters/{character_id}/players/{player_id}

Permanently deletes a conversation, all its messages, and all memories this character holds about the player. Uploaded chat images are soft-deleted.

Response​

204 No Content, with an empty body.

:::warning Changed from the legacy route The older DELETE /api/agents/{agent_id}/players/{player_id} returned 200 with {"message": "Player conversation deleted"}. The canonical route returns 204 and no body, so do not try to parse the response. :::

Responds with 404 when this player has no conversation with the character.

Example​

curl -X DELETE https://api.estuary-ai.com/api/v1/characters/550e8400-e29b-41d4-a716-446655440000/players/player_xyz \
-H "X-API-Key: est_your_api_key"