Skip to main content

Chat Management - POST /external/chat

Create and manage chat sessions for seamless conversations with your Optimly AI agent. Chat sessions provide context continuity and help track user interactions over time.

Create New Chat Session

Endpoint

POST /external/chat

Authentication

Authorization: Bearer YOUR_AGENT_ACCESS_TOKEN

Request Body

{
"client_id": "string",
"ai_enabled": true,
"metadata": {
"source": "string",
"user_agent": "string",
"initial_url": "string"
}
}

Parameters

ParameterTypeRequiredDescription
client_idstringYesUnique identifier for the client/user
ai_enabledbooleanNoWhether AI responses are enabled (default: true)
metadataobjectNoAdditional session metadata

Response

{
"chat_id": "chat_abc123",
"agent_id": "agent_456",
"client_id": "user_789",
"created_at": "2025-06-16T10:30:00Z",
"ai_enabled": true,
"lead_collected": false,
"status": "active"
}

Get Chat Messages

Endpoint

GET /external/chat/{chat_id}/messages

Authentication

Authorization: Bearer YOUR_AGENT_ACCESS_TOKEN

Response

[
{
"message_id": "msg_123",
"chat_id": "chat_abc123",
"sender": "user",
"content": "Hello, I need help with my order",
"timestamp": "2025-06-16T10:30:00Z",
"metadata": {
"source": "website"
}
},
{
"message_id": "msg_124",
"chat_id": "chat_abc123",
"sender": "assistant",
"content": "I'd be happy to help you with your order. Can you provide your order number?",
"timestamp": "2025-06-16T10:30:15Z",
"metadata": {
"processing_time": 1.2,
"tools_used": []
}
}
]

Get Client Chats

Endpoint

GET /external/chat/{client_id}/chats

Authentication

Authorization: Bearer YOUR_AGENT_ACCESS_TOKEN

Response

[
{
"chat_id": "chat_abc123",
"agent_id": "agent_456",
"client_id": "user_789",
"created_at": "2025-06-16T10:30:00Z",
"last_activity": "2025-06-16T11:45:00Z",
"message_count": 8,
"ai_enabled": true,
"lead_collected": true,
"status": "active"
},
{
"chat_id": "chat_def456",
"agent_id": "agent_456",
"client_id": "user_789",
"created_at": "2025-06-15T14:20:00Z",
"last_activity": "2025-06-15T14:35:00Z",
"message_count": 3,
"ai_enabled": true,
"lead_collected": false,
"status": "closed"
}
]

Usage Examples

JavaScript - Create Chat and Send Message

class OptimlyChat {
constructor(accessToken, baseUrl = 'https://api.optimly.io') {
this.accessToken = accessToken;
this.baseUrl = baseUrl;
this.headers = {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
};
}

async createChat(clientId, metadata = {}) {
const response = await fetch(`${this.baseUrl}/external/chat`, {
method: 'POST',
headers: this.headers,
body: JSON.stringify({
client_id: clientId,
ai_enabled: true,
metadata
})
});

if (!response.ok) {
throw new Error(`Failed to create chat: ${response.statusText}`);
}

return await response.json();
}

async getChatMessages(chatId) {
const response = await fetch(`${this.baseUrl}/external/chat/${chatId}/messages`, {
headers: this.headers
});

if (!response.ok) {
throw new Error(`Failed to get messages: ${response.statusText}`);
}

return await response.json();
}

async getClientChats(clientId) {
const response = await fetch(`${this.baseUrl}/external/chat/${clientId}/chats`, {
headers: this.headers
});

if (!response.ok) {
throw new Error(`Failed to get chats: ${response.statusText}`);
}

return await response.json();
}
}

// Usage example
const chat = new OptimlyChat('your_access_token');

// Create a new chat session
const newChat = await chat.createChat('user_123', {
source: 'website',
user_agent: navigator.userAgent,
initial_url: window.location.href
});

console.log('New chat created:', newChat.chat_id);

// Get chat history
const messages = await chat.getChatMessages(newChat.chat_id);
console.log('Chat history:', messages);

Python - Chat Management

import requests
from typing import Dict, List, Optional

class OptimlyChat:
def __init__(self, access_token: str, base_url: str = 'https://api.optimly.io'):
self.access_token = access_token
self.base_url = base_url
self.headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}

def create_chat(self, client_id: str, metadata: Optional[Dict] = None) -> Dict:
"""Create a new chat session."""
payload = {
'client_id': client_id,
'ai_enabled': True
}

if metadata:
payload['metadata'] = metadata

response = requests.post(
f'{self.base_url}/external/chat',
json=payload,
headers=self.headers
)
response.raise_for_status()
return response.json()

def get_chat_messages(self, chat_id: str) -> List[Dict]:
"""Get all messages from a chat session."""
response = requests.get(
f'{self.base_url}/external/chat/{chat_id}/messages',
headers=self.headers
)
response.raise_for_status()
return response.json()

def get_client_chats(self, client_id: str) -> List[Dict]:
"""Get all chats for a specific client."""
response = requests.get(
f'{self.base_url}/external/chat/{client_id}/chats',
headers=self.headers
)
response.raise_for_status()
return response.json()

# Usage example
chat_manager = OptimlyChat('your_access_token')

# Create new chat
new_chat = chat_manager.create_chat(
client_id='user_123',
metadata={
'source': 'python_app',
'version': '1.0.0'
}
)

print(f"Created chat: {new_chat['chat_id']}")

# Get chat history
messages = chat_manager.get_chat_messages(new_chat['chat_id'])
print(f"Found {len(messages)} messages")

React Hook for Chat Management

import { useState, useEffect, useCallback } from 'react';

export function useOptimlyChat(accessToken, clientId) {
const [chats, setChats] = useState([]);
const [currentChat, setCurrentChat] = useState(null);
const [messages, setMessages] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);

const baseUrl = 'https://api.optimly.io';
const headers = {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
};

const createChat = useCallback(async (metadata = {}) => {
setLoading(true);
setError(null);

try {
const response = await fetch(`${baseUrl}/external/chat`, {
method: 'POST',
headers,
body: JSON.stringify({
client_id: clientId,
ai_enabled: true,
metadata: {
source: 'react_app',
...metadata
}
})
});

if (!response.ok) {
throw new Error(`Failed to create chat: ${response.statusText}`);
}

const newChat = await response.json();
setCurrentChat(newChat);
setMessages([]);

// Refresh chats list
await loadClientChats();

return newChat;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, [accessToken, clientId]);

const loadChatMessages = useCallback(async (chatId) => {
setLoading(true);
setError(null);

try {
const response = await fetch(`${baseUrl}/external/chat/${chatId}/messages`, {
headers
});

if (!response.ok) {
throw new Error(`Failed to load messages: ${response.statusText}`);
}

const chatMessages = await response.json();
setMessages(chatMessages);

return chatMessages;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, [accessToken]);

const loadClientChats = useCallback(async () => {
setLoading(true);
setError(null);

try {
const response = await fetch(`${baseUrl}/external/chat/${clientId}/chats`, {
headers
});

if (!response.ok) {
throw new Error(`Failed to load chats: ${response.statusText}`);
}

const clientChats = await response.json();
setChats(clientChats);

return clientChats;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
}, [accessToken, clientId]);

const switchToChat = useCallback(async (chat) => {
setCurrentChat(chat);
await loadChatMessages(chat.chat_id);
}, [loadChatMessages]);

// Load client chats on mount
useEffect(() => {
if (accessToken && clientId) {
loadClientChats();
}
}, [accessToken, clientId, loadClientChats]);

return {
chats,
currentChat,
messages,
loading,
error,
createChat,
loadChatMessages,
loadClientChats,
switchToChat
};
}

// Usage in component
function ChatInterface({ accessToken, clientId }) {
const {
chats,
currentChat,
messages,
loading,
error,
createChat,
switchToChat
} = useOptimlyChat(accessToken, clientId);

const handleNewChat = async () => {
try {
await createChat({
page_url: window.location.href,
user_agent: navigator.userAgent
});
} catch (error) {
console.error('Failed to create chat:', error);
}
};

if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;

return (
<div className="chat-interface">
<div className="chat-sidebar">
<button onClick={handleNewChat}>New Chat</button>

<div className="chat-list">
{chats.map(chat => (
<div
key={chat.chat_id}
className={`chat-item ${currentChat?.chat_id === chat.chat_id ? 'active' : ''}`}
onClick={() => switchToChat(chat)}
>
<div className="chat-preview">
Chat {chat.chat_id.slice(-6)}
</div>
<div className="chat-meta">
{chat.message_count} messages
</div>
</div>
))}
</div>
</div>

<div className="chat-main">
{currentChat ? (
<div className="messages">
{messages.map(message => (
<div key={message.message_id} className={`message ${message.sender}`}>
<div className="content">{message.content}</div>
<div className="timestamp">{new Date(message.timestamp).toLocaleTimeString()}</div>
</div>
))}
</div>
) : (
<div className="no-chat">Select a chat or create a new one</div>
)}
</div>
</div>
);
}

Best Practices

1. Client ID Management

Use consistent, unique client IDs to track users across sessions:

// Generate or retrieve client ID
let clientId = localStorage.getItem('optimly_client_id');
if (!clientId) {
clientId = `client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
localStorage.setItem('optimly_client_id', clientId);
}

2. Chat Session Lifecycle

Manage chat sessions appropriately for your use case:

// For customer support - create new chat per issue
const supportChat = await createChat(clientId, {
type: 'support',
issue_category: 'billing'
});

// For general assistance - reuse existing chat
const existingChats = await getClientChats(clientId);
const activeChat = existingChats.find(chat => chat.status === 'active');

const chatId = activeChat ? activeChat.chat_id : (await createChat(clientId)).chat_id;

3. Message History Management

Load appropriate message history for context:

// Load recent messages for context
const messages = await getChatMessages(chatId);
const recentMessages = messages.slice(-10); // Last 10 messages

// Display in UI with proper formatting
recentMessages.forEach(message => {
displayMessage(message.sender, message.content, message.timestamp);
});

4. Error Handling

Implement robust error handling for chat operations:

async function safeCreateChat(clientId, metadata = {}) {
try {
return await createChat(clientId, metadata);
} catch (error) {
if (error.status === 401) {
// Handle authentication error
console.error('Invalid access token');
return null;
} else if (error.status === 429) {
// Handle rate limiting
console.error('Rate limit exceeded, retrying in 60 seconds');
setTimeout(() => safeCreateChat(clientId, metadata), 60000);
return null;
} else {
console.error('Failed to create chat:', error);
throw error;
}
}
}

Chat Status Management

Chats can have different statuses based on their activity:

StatusDescription
activeCurrently active conversation
inactiveNo recent activity but not closed
closedExplicitly closed conversation
escalatedTransferred to human support

Rate Limits

  • 50 chat creations per hour per access token
  • 200 message retrievals per hour per access token
  • 100 chat list requests per hour per access token

Common Use Cases

Website Chat Widget

// Initialize chat for website visitor
const chat = await createChat(getVisitorId(), {
source: 'website',
page_url: window.location.href,
referrer: document.referrer
});

Mobile App Support

// Create support chat in mobile app
const chat = await createChat(getUserId(), {
source: 'mobile_app',
app_version: '2.1.0',
device_type: 'iOS'
});

Customer Portal Integration

// Authenticated customer starting chat
const chat = await createChat(customer.id, {
source: 'customer_portal',
customer_tier: customer.tier,
subscription_status: customer.subscription.status
});

Next Steps