Documentation Index
Fetch the complete documentation index at: https://docs.plura.ai/llms.txt
Use this file to discover all available pages before exploring further.
Session Lifecycle
Starting a New Conversation
- Set
sessionId to null in the connection URL
- Save the
session_id from the first received message for future reconnections
Resuming a Previous Conversation
- Use the stored
session_id in the connection URL
- The AI maintains full context from previous messages
JavaScript (Browser)
let ws;
let heartbeatInterval;
let sessionId = localStorage.getItem('plura_session_id') || 'null';
async function initializeSession(flowId, leadData) {
const response = await fetch('https://hooks.plura.ai/webchat/session', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ record: leadData, flow_id: flowId })
});
return response.json();
}
function connectWebSocket(flowId, sessionId = 'null') {
ws = new WebSocket(
`wss://wss.plura.ai/webchat/flow/${flowId}/session/${sessionId}/r/true`
);
ws.onopen = () => {
heartbeatInterval = setInterval(sendHeartbeat, 15000);
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
switch (data.type) {
case 'session':
sessionId = data.session_id;
localStorage.setItem('plura_session_id', sessionId);
break;
case 'message':
displayMessage(data.content, 'ai');
break;
}
};
ws.onclose = () => clearInterval(heartbeatInterval);
}
function sendMessage(text) {
ws.send(JSON.stringify({ message: text, type: 'message' }));
}
function sendHeartbeat() {
const now = new Date();
const offset = -now.getTimezoneOffset();
const h = Math.floor(Math.abs(offset) / 60);
const m = Math.abs(offset) % 60;
const tz = `${offset >= 0 ? '+' : '-'}${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}`;
ws.send(JSON.stringify({
message: { stamp: now.toISOString().slice(0, 19), tz },
type: 'heartbeat'
}));
}
// Full flow: initialize session then connect
async function startChat(flowId, leadData) {
const session = await initializeSession(flowId, leadData);
connectWebSocket(session.flow_id, session.session);
}
startChat('your-flow-id', {
phone: '+15551234567',
first_name: 'John',
last_name: 'Smith'
});
Python
import websockets
import asyncio
import json
import requests
from datetime import datetime, timezone
class PluraWebChat:
def __init__(self, flow_id):
self.flow_id = flow_id
self.session_id = 'null'
self.ws = None
self.heartbeat_task = None
def initialize_session(self, lead_data):
response = requests.post(
'https://hooks.plura.ai/webchat/session',
json={'record': lead_data, 'flow_id': self.flow_id},
headers={'Content-Type': 'application/json'}
)
session_data = response.json()
self.session_id = session_data['session']
self.flow_id = session_data['flow_id']
return session_data
async def connect(self):
url = f"wss://wss.plura.ai/webchat/flow/{self.flow_id}/session/{self.session_id}/r/true"
self.ws = await websockets.connect(url)
self.heartbeat_task = asyncio.create_task(self._heartbeat_loop())
await self._receive_messages()
async def _receive_messages(self):
async for message in self.ws:
data = json.loads(message)
if data['type'] == 'session':
self.session_id = data['session_id']
elif data['type'] == 'message':
print(f"AI: {data['content']}")
async def send_message(self, text):
await self.ws.send(json.dumps({'message': text, 'type': 'message'}))
async def _heartbeat_loop(self):
while True:
await asyncio.sleep(15)
now = datetime.now(timezone.utc)
await self.ws.send(json.dumps({
'message': {'stamp': now.strftime('%Y-%m-%dT%H:%M:%S'), 'tz': '+00:00'},
'type': 'heartbeat'
}))
async def close(self):
if self.heartbeat_task:
self.heartbeat_task.cancel()
if self.ws:
await self.ws.close()
Critical Requirements
Heartbeat is required. Send every 15 seconds or the connection will drop and the user will appear offline in the dashboard.
- Heartbeat — every 15 seconds, no exceptions
- Session storage — persist
session_id client-side for conversation continuity
- Session init is optional — only needed when passing lead data; use
session=null for anonymous chat
- Message order — messages are delivered in order and each user message gets a
recv confirmation