Below is a complete JavaScript example: a session with user context, a message with a streamed answer, and error handling.
const API = 'https://widget-api.prosecaptain.com/api/v2/widget';
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_TOKEN'
};
// New session
async function startSession(context) {
const res = await fetch(`${API}/thread`, {
method: 'POST',
headers,
body: JSON.stringify({ widget_id: 'WIDGET_ID', context })
});
if (!res.ok) throw new Error(`thread: ${res.status}`);
return (await res.json()).session_id;
}
// Message without streaming
async function ask(sessionId, message) {
const res = await fetch(`${API}/message`, {
method: 'POST',
headers,
body: JSON.stringify({ session_id: sessionId, message, widget_id: 'WIDGET_ID' })
});
if (res.status === 429) throw new Error('Too many requests, try again shortly');
if (!res.ok) throw new Error(`message: ${res.status}`);
return res.json();
}
// Message with streaming (Server-Sent Events)
async function askStream(sessionId, message, onDelta) {
const res = await fetch(`${API}/message`, {
method: 'POST',
headers,
body: JSON.stringify({ session_id: sessionId, message, widget_id: 'WIDGET_ID', stream: true })
});
const reader = res.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
for (;;) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const events = buffer.split('\n\n');
buffer = events.pop();
for (const raw of events) {
const event = raw.match(/^event: (.*)$/m)?.[1];
const data = raw.match(/^data: (.*)$/m)?.[1];
if (event === 'delta' && data) onDelta(JSON.parse(data));
}
}
}
const sessionId = await startSession({ current_page: 'Category: Sports' });
const answer = await ask(sessionId, 'Show me available running shoe models');
console.log(answer);
Tip
In production, add retries for network failures and 429 responses. Only send context that helps the assistant answer.