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.


New to this? Web chat explains what it does and when to use it, without the API detail.