Channels & Embeds
Embedded web chat
Add a text chat with your OnCore assistant to any website.
Embedded web chat lets visitors text with a OnCore assistant from your website. Your backend mints a short-lived session token; the browser then talks to OnCore directly with that token — your API key never leaves your server.
Keep the API key server-side
The tenant API key is a server-side secret. Call /web-chat/session from your backend, never from browser JavaScript. The browser only ever holds the short-lived session token.
Integration flow#
Mint a session token (backend)#
Call POST /web-chat/session with your API key. phoneNumber must be E.164 and assigned to one of your tenant's assistants — it selects which assistant the visitor chats with.
curl -X POST https://core-api.heysadie.ai/web-chat/session \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "phoneNumber": "+15555550123", "visitorId": "usr_abc123" }'{
"sessionToken": "eyJhbGciOi...",
"expiresIn": 1800
}visitorId is optional: a stable, unique-per-end-user identifier you control (your user id, or a random id persisted in the visitor's cookie/localStorage; 1–128 characters, letters, digits, and . _ : -). Supplying it keeps the conversation continuous across token refreshes and page reloads. Omit it for an ephemeral one-shot session.
Return sessionToken to your browser. The token has a 30-minute TTL (expiresIn seconds); after it expires the browser must request a fresh token from your backend.
Send messages (browser)#
The browser authenticates with the session token as a Bearer token — no API key involved. The visitor identity is sealed inside the token and cannot be spoofed from the browser.
const res = await fetch("https://core-api.heysadie.ai/web-chat/messages", {
method: "POST",
headers: {
Authorization: `Bearer ${sessionToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ text: "Do you have a table for two tonight?" }),
});
const { reply } = await res.json();text is optional (max 4,000 characters) — omit it or send an empty string to trigger the assistant's opening greeting, which is a good way to start the widget.
{
"reply": "Hi! I'd be happy to help with your reservation. What's your name?"
}End the conversation (browser)#
When the visitor closes the chat, end the conversation explicitly:
await fetch("https://core-api.heysadie.ai/web-chat/end", {
method: "POST",
headers: { Authorization: `Bearer ${sessionToken}` },
});
// -> { "ended": true }Errors#
| Status | Cause |
|---|---|
400 | phoneNumber missing or not E.164 (session endpoint); text over 4,000 characters (messages endpoint) |
401 | Missing, invalid, or expired Authorization header |
404 | Phone number unknown or not assigned to your tenant — returns the bare { "error": "not_found" } body (see Errors) |
502 | Messaging backend returned a non-2xx response |
503 | Messaging backend unreachable |
CORS
The /web-chat/messages and /web-chat/end routes are callable from any origin — the per-request session token is the security boundary, not an origin allowlist. /web-chat/session is deliberately not CORS-exposed, since it must only ever be called server-side.
Web-chat conversations appear alongside other channels in your conversations and fire the messaging webhooks when they start and end.
See the API reference for the full endpoint specification.