In-depth: Conversations

The Sensay API provides access to conversation data and messages through specialized endpoints that use cursor-based pagination for efficient navigation through large message histories.

Conversation mentions

The mentions endpoint allows you to retrieve conversation messages grouped into "mention groups" (containing assistant replies and context) and "placeholder groups" (representing collapsed user-only messages).

Conversation messages

The messages endpoint allows you to retrieve conversation messages. This is useful for expanding placeholders received from the mentions endpoint.

Cursor-based pagination

Conversation endpoints use cursor-based pagination with unique identifiers (UUIDs) to navigate through datasets. This approach is efficient for large datasets and handles concurrent changes gracefully.

Parameters
  • limit: Number of items to fetch (1-100)
  • beforeUUID: Return items before this UUID (excluding the UUID itself)
  • afterUUID: Return items after this UUID (excluding the UUID itself)

Basic usage

Get the first page (latest mentions):

curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations/{conversationUUID}/mentions?limit=20" \
  -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \
  -H "X-API-Version: $API_VERSION" \
  -H "Content-Type: application/json"

Response:

{
  "success": true,
  "items": [
    {
      "type": "message",
      "uuid": "03db5651-cb61-4bdf-9ef0-89561f7c9c53",
      "content": "Hello, how are you?",
      "role": "user",
      "createdAt": "2024-09-24T09:09:55.66709+00:00",
      "source": "web",
      "replicaUUID": "f0e4c2f7-ae27-4b35-89bf-7cf729a73687"
    },
    {
      "type": "message",
      "uuid": "04ea3f1b-df72-4c98-a8f1-2ef820b5c94d",
      "content": "I'm doing well, thank you for asking!",
      "role": "assistant",
      "createdAt": "2024-09-24T09:10:15.33421+00:00",
      "source": "web",
      "replicaUUID": "f0e4c2f7-ae27-4b35-89bf-7cf729a73687"
    },
    {
      "type": "placeholder",
      "count": 15
    }
  ]
}

Navigation

Get the next page (older mentions):

# Use the UUID of the last message from the previous response
curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations/{conversationUUID}/mentions?limit=20&beforeUUID=03db5651-cb61-4bdf-9ef0-89561f7c9c53" \
  -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \
  -H "X-API-Version: $API_VERSION" \
  -H "Content-Type: application/json"

Get newer mentions:

# Use the UUID of the first message from the current page
curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations/{conversationUUID}/mentions?limit=20&afterUUID=ec46b4db-3f0d-4392-b0f5-9fe327922e8a" \
  -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \
  -H "X-API-Version: $API_VERSION" \
  -H "Content-Type: application/json"
Implementation pattern
async function loadNextPage(lastMessageUUID) {
  const response = await fetch(
    `/mentions?limit=20&beforeUUID=${lastMessageUUID}`
  );
  return response.json();
}

async function loadPreviousPage(firstMessageUUID) {
  const response = await fetch(
    `/mentions?limit=20&afterUUID=${firstMessageUUID}`
  );
  return response.json();
}

// Usage
const firstPage = await fetch('/mentions?limit=20');
const data = await firstPage.json();

// Get the last message UUID for next page
const lastMessage = data.items
  .filter(item => item.type === 'message')
  .pop();

if (lastMessage) {
  const nextPage = await loadNextPage(lastMessage.uuid);
}

Placeholder expansion

Expand a placeholder chronologically before a known message UUID:

# Use the UUID of the first message after the placeholder
curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations/{conversationUUID}/messages?limit=20&beforeUUID=03db5651-cb61-4bdf-9ef0-89561f7c9c53" \
  -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \
  -H "X-API-Version: $API_VERSION" \
  -H "Content-Type: application/json"

Expand a placeholder chronologically after a known message UUID:

# Use the UUID of the last message before the placeholder
curl -X GET "https://api.sensay.io/v1/replicas/{replicaUUID}/conversations/{conversationUUID}/mentions?limit=20&afterUUID=ec46b4db-3f0d-4392-b0f5-9fe327922e8a" \
  -H "X-ORGANIZATION-SECRET: $ORGANIZATION_SECRET" \
  -H "X-API-Version: $API_VERSION" \
  -H "Content-Type: application/json"
Implementation pattern
async function expandPlaceholderBefore(firstMessageUUID) {
  const response = await fetch(
    `/messages?limit=20&afterUUID=${firstMessageUUID}`
  );
  return response.json();
}

async function expandPlaceholderAfter(lastMessageUUID) {
  const response = await fetch(
    `/messages?limit=20&afterUUID=${lastMessageUUID}`
  );
  return response.json();
}

// Usage
const mentions = await fetch('/mentions?limit=20');
const { items } = await mentions.json();

const placeholders = items.reduce((acc, item, ix, array) => {
  if (item.type === 'placeholder') {
    acc.push({
      ...item,
      nextOlderMessageUUID: array[ix - 1]?.uuid,
      nextNewerMessageUUID: array[ix + 1]?.uuid
    })
  }
  return acc;
}, [])

// Expand the most recent placeholder
const messages = await fetch(`/messages?afterUUID=${placeholders[placeholders.length-1].nextOlderMessageUUID}`)

Understanding message types

Message items

Messages represent actual conversation content with full details:

  • uuid: Unique identifier for cursor navigation
  • content: The message text
  • role: Either "user" or "assistant"
  • createdAt: Timestamp when the message was created
  • source: Where the message originated (web, telegram, discord, etc.)
  • replicaUUID: The replica involved in this conversation

Placeholder items

Placeholders represent collapsed groups of messages to improve navigation:

  • type: Always "placeholder"
  • count: Number of messages represented by this placeholder

Placeholders typically represent stretches of user-only messages between assistant interactions, allowing you to focus on the most relevant parts of long conversations.

Best practices

Performance

  1. Choose appropriate limits:

    • 10-50 items for UI lists
    • Up to 100 for data processing
  2. Cache responses when possible:

    • Cursor positions are stable and cache-friendly
    • Message content rarely changes once created

Error handling

// Handle invalid cursors
try {
  const response = await fetch(`/mentions?beforeUUID=${uuid}`);
  if (response.status === 400) {
    // UUID doesn't exist in this conversation
    // Fall back to loading from the beginning
    return fetch('/mentions?limit=20');
  }
} catch (error) {
  console.error('Conversation pagination error:', error);
}

UI considerations

  1. Loading states: Always show loading indicators during pagination requests
  2. Empty states: Handle conversations with no assistant interactions
  3. Error states: Provide retry mechanisms for failed requests
  4. Real-time updates: Consider how new messages affect cursor positions