Skip to content

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.

Terminal
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" }'
200 response
{
  "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.

browser.js
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.

200 response
{
  "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:

browser.js
await fetch("https://core-api.heysadie.ai/web-chat/end", {
  method: "POST",
  headers: { Authorization: `Bearer ${sessionToken}` },
});
// -> { "ended": true }

Errors#

StatusCause
400phoneNumber missing or not E.164 (session endpoint); text over 4,000 characters (messages endpoint)
401Missing, invalid, or expired Authorization header
404Phone number unknown or not assigned to your tenant — returns the bare { "error": "not_found" } body (see Errors)
502Messaging backend returned a non-2xx response
503Messaging 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.