Messaging & channels
Web chat
Put the same OnCore assistant that answers your phone on your website as a text chat.
The assistant that answers your phone can hold the same conversation in writing, as a chat on your own website. Same assistant, same knowledge, typed instead of spoken.
Overview#
Web chat puts your OnCore assistant on your own website as a text conversation. A visitor types a question into a chat window on your page and the assistant replies in writing. It is the same assistant that answers when customers call or text your number. You build the chat window to match your site's look; OnCore supplies the conversation behind it. Your website talks to OnCore with short-lived session passes, so your account credentials never appear anywhere a visitor could find them.
- Answer questions on your site around the clock: visitors asking about pricing, availability, or opening hours get an immediate written answer instead of a contact form.
- Give one consistent front door everywhere: phone, SMS, and website chat are all handled by the same assistant, so updating it in one place updates every channel.
- Open with a greeting: the chat can start with the assistant's own opening message, inviting the visitor in before they type anything.
- Keep the thread for returning visitors: tag each visitor with an identifier from your site and their conversation carries on across page reloads instead of starting over.
- Feed every chat into your systems: each finished conversation delivers a transcript, summary, and analysis to your servers, and the full history is searchable and exportable through the API.
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 to 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 is 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, ended } = 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?",
"ended": false
}ended is true when the conversation is over: the assistant has just said goodbye, or the visitor answered that goodbye. Show the visitor that the chat has closed and that a new message starts a new conversation.
For a short window after a conversation ends, the visitor's next message is handled like this:
- A short goodbye ("thanks, you too!", "ok", 👍) does not open a new conversation. It returns
{ "reply": "", "ended": true }, so render nothing whenreplyis empty. - Anything else, including "hi" or a question, opens a new conversation and returns
ended: false. The assistant answers it directly, without the opening greeting, and sees the last few messages of the previous conversation: "yes" or "no, tomorrow evening" is read as a follow-up, and a "hi" gets a reply that picks up where the visitor left off.
After the window, a new message starts a new conversation with the greeting as usual. The window follows the visitor identity in the session token: if your page mints a new session without the same visitorId, the next message comes from a new visitor and starts fresh.
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.
Limits & FAQ#
- Web chat is text only; a chat message can be up to 4,000 characters.
- A session pass lasts 30 minutes. When it expires, your page fetches a fresh one from your server. With a visitor identifier attached, the conversation continues where it left off; without one, a new session starts a new conversation.
- OnCore provides the conversation service, not a ready-made chat widget; the chat window on your page is yours to design, in any framework.
Is it the same assistant as our phone line? Yes. The chat is keyed to a phone number you own, and the assistant assigned to that number answers both. Update its knowledge in one place and every channel follows.
Can we see the chats afterwards? Yes. Every web-chat conversation lands in your conversation history alongside SMS and WhatsApp threads, with its messages and summary. Query or export them through the Conversations API, or receive each one as it ends via the end-of-conversation report.
What if the visitor replies to the assistant's goodbye? A short goodbye right after the chat ends is not answered and does not start a new conversation, so it creates no extra conversation record or webhook. The response carries ended: true, which your page can use to show that the chat has closed. Any other message in that window, even a "hi", starts a new conversation and gets a direct answer that takes the previous conversation into account.
What happens when the visitor closes the chat? Your page tells OnCore the conversation is over, and the end-of-conversation report fires with the transcript and analysis, so your follow-up starts the moment the chat ends.
Next steps#
- Conversations: list, filter and export finished chats.
- End-of-conversation report: receive each chat as it ends.
- Web Chat API: the full endpoint specification.