GET /api/dev/v1/chatbots/{chatbot_id}/integrations/rest-apiPATCH /api/dev/v1/chatbots/{chatbot_id}/integrations/rest-apiAuthorization: Bearer <api-key>GET /api/dev/v1/chatbots/{chatbot_id}/integrations/rest-apiPATCH /api/dev/v1/chatbots/{chatbot_id}/integrations/rest-apiAuthorization: Bearer <api-key>
Web Widget Integration
Embed a real-time chat widget on any website. The widget loads asynchronously, connects over Socket.IO, and supports full conversation history, buttons, lists, and media messages.
Create Web Integration
http
POST /api/dev/v1/chatbots/{chatbot_id}/integrations/webAuthorization: Bearer <api-key>Content-Type: application/jsonPOST /api/dev/v1/chatbots/{chatbot_id}/integrations/webAuthorization: Bearer <api-key>Content-Type: application/json
Body
namestringrequired
A friendly name for this web integration.
allowed_domainsarrayoptional
List of domains allowed to load the widget (e.g. ["yoursite.com", "app.yoursite.com"]). Leave empty to allow all domains.
greeting_messagestringoptional
The first message shown when a visitor opens the widget.
widget_configobjectoptional
Appearance and behaviour overrides - see the Widget Config reference below.
widget_config fields
bot_display_namestringoptional
Name shown in the widget header and on bot messages. Defaults to "Assistant".
primary_colorstringoptional
Hex color for the bubble, header, and user messages. Defaults to "#0066ff".
secondary_colorstringoptional
Hex color for bot message bubbles. Defaults to "#f0f4ff".
background_colorstringoptional
Hex color for the chat message area background.
bubble_textstringoptional
Text shown on the floating bubble button. Defaults to "Need Help?".
bot_avatar_iconstringoptional
Icon key for the bot avatar. One of: "" (Sarufi default), "robot", "headset", "sparkle", "heart", "store", "graduation", "chat".
font_sizenumberoptional
Base font size in pixels (12–24). Defaults to 13.5.
positionstringoptional
Widget placement. One of "bottom-right" (default) or "bottom-left".
widthnumberoptional
Chat window width in pixels (280–600). Defaults to 380.
heightnumberoptional
Chat window height in pixels (400–800). Defaults to 600.
allowed_pathsarrayoptional
URL path patterns where the widget should appear. Supports exact paths ("/contact") and wildcard prefix matching ("/shop/*"). When null or empty the widget appears on every page.
bash
curl -X POST https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{ "name": "Main Site Widget", "allowed_domains": ["yoursite.com"], "greeting_message": "Hi! How can I help you today?", "widget_config": { "bot_display_name": "Aria", "primary_color": "#0066ff", "bubble_text": "Need Help?", "position": "bottom-right", "allowed_paths": ["/contact", "/support/*"] } }'curl -X POST https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{ "name": "Main Site Widget", "allowed_domains": ["yoursite.com"], "greeting_message": "Hi! How can I help you today?", "widget_config": { "bot_display_name": "Aria", "primary_color": "#0066ff", "bubble_text": "Need Help?", "position": "bottom-right", "allowed_paths": ["/contact", "/support/*"] } }'
python
import requestsresponse = requests.post( "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web", headers={"Authorization": "Bearer <your-api-key>"}, json={ "name": "Main Site Widget", "allowed_domains": ["yoursite.com"], "greeting_message": "Hi! How can I help you today?", "widget_config": { "bot_display_name": "Aria", "primary_color": "#0066ff", "bubble_text": "Need Help?", "position": "bottom-right", "allowed_paths": ["/contact", "/support/*"], }, },)print(response.json())import requestsresponse = requests.post( "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web", headers={"Authorization": "Bearer <your-api-key>"}, json={ "name": "Main Site Widget", "allowed_domains": ["yoursite.com"], "greeting_message": "Hi! How can I help you today?", "widget_config": { "bot_display_name": "Aria", "primary_color": "#0066ff", "bubble_text": "Need Help?", "position": "bottom-right", "allowed_paths": ["/contact", "/support/*"], }, },)print(response.json())
javascript
const response = await fetch( "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web", { method: "POST", headers: { "Authorization": "Bearer <your-api-key>", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Main Site Widget", allowed_domains: ["yoursite.com"], greeting_message: "Hi! How can I help you today?", widget_config: { bot_display_name: "Aria", primary_color: "#0066ff", bubble_text: "Need Help?", position: "bottom-right", allowed_paths: ["/contact", "/support/*"], }, }), },);const data = await response.json();const response = await fetch( "https://developers.sarufi.io/api/dev/v1/chatbots/<chatbot-id>/integrations/web", { method: "POST", headers: { "Authorization": "Bearer <your-api-key>", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Main Site Widget", allowed_domains: ["yoursite.com"], greeting_message: "Hi! How can I help you today?", widget_config: { bot_display_name: "Aria", primary_color: "#0066ff", bubble_text: "Need Help?", position: "bottom-right", allowed_paths: ["/contact", "/support/*"], }, }), },);const data = await response.json();
lazyOnload loads the widget after all critical page resources finish. Use it in app/layout.tsx for site-wide embeds, or scope it to a nested layout for specific route groups only.
Angular SSR (Universal)
Wrap the script injection in an isPlatformBrowser(this.platformId) check to prevent it running during server-side rendering.
Shopify Online Store 2.0
On OS2.0 themes you can add a custom snippet under snippets/sarufi-widget.liquid and render it with {%- render 'sarufi-widget' -%} to keep theme.liquid tidy.
JavaScript API
The widget exposes window.SarufiWidget with methods you can call from your page's JavaScript. Both methods can be called before or after the widget script loads — they take effect immediately or queue until the widget connects.
Identify the visitor
Attach a visitor identity so the same person resumes their conversation across devices, sessions, and reconnects.
html
<script> // Call after your login logic — pass the user's email or phone number SarufiWidget.identify("alice@acme.com");</script><script> // Call after your login logic — pass the user's email or phone number SarufiWidget.identify("alice@acme.com");</script>
Rules:
Accepts an email or phone number
Phone numbers are normalized to E.164 server-side (0712..., +255712..., 255 712 ... all map to the same visitor)
Invalid or synthetic emails are rejected (connection refused) — only pass real addresses
Sanitized to [A-Za-z0-9@._-], max 100 characters
When the same user_id connects again, the backend resumes their latest conversation
Omit the call entirely for anonymous visitors — behavior is unchanged
Send contact details
Pass extra visitor metadata that agents see in the conversation context panel. Useful for surfacing account info, plan tier, or any business-specific context.
Plain { key: value } object — labels are up to you
Keys are normalized to snake_case server-side ("Merchant account name" → merchant_account_name)
Values must be scalars (string, number, boolean) — nested objects are dropped
Max 13 fields, each value max 300 characters
Details are merged on each reconnect: new keys are added, existing keys are updated, old keys are retained
Stored once the visitor sends their first message
Full example
html
<script src="https://sarufi.io/widget.js" data-widget-key="wk_YOUR_WIDGET_KEY" async></script><script> // After your app authenticates the user: SarufiWidget.identify("alice@acme.com"); SarufiWidget.setContactDetails({ "Name": "Alice Mongi", "Merchant account name": "Acme Ltd", "Plan": "Pro" });</script><script src="https://sarufi.io/widget.js" data-widget-key="wk_YOUR_WIDGET_KEY" async></script><script> // After your app authenticates the user: SarufiWidget.identify("alice@acme.com"); SarufiWidget.setContactDetails({ "Name": "Alice Mongi", "Merchant account name": "Acme Ltd", "Plan": "Pro" });</script>
Independent features
identify() and setContactDetails() are fully independent. You can use one without the other, or both together. Identity drives session continuity; contact details provide extra context visible to agents.
Path-Based Visibility
By default the widget appears on every page. Use allowed_paths inside widget_config to restrict it to specific pages.
How matching works
Pattern
Matches
"/contact"
Exactly /contact
"/shop/*"
/shop, /shop/, /shop/shoes, /shop/shoes/nike
"/docs/*"
/docs, /docs/getting-started, /docs/api/auth
When a visitor navigates to a page not in allowed_paths:
The widget is hidden (display: none)
The Socket.IO connection is disconnected - no idle connections on restricted pages
When they navigate back to an allowed page:
The widget reappears
The socket reconnects automatically, resuming the conversation from session history
SPA route changes
The widget listens for both popstate (browser back/forward) and intercepts history.pushState / history.replaceState to handle client-side navigation in React, Vue, Angular, and Next.js apps - no extra configuration needed.
MCP (Model Context Protocol) integrations give LLM agents access to tools hosted on external servers — order lookups, CRM queries, ticketing systems, internal APIs — without writing custom executor code.
Unlike channel integrations (WhatsApp, REST API, web widget), MCP integrations are many-per-chatbot: each chatbot can have multiple MCP servers registered simultaneously.
Knowledge Base or MCP?
Knowledge Base — ground answers in your own documents via RAG. Best for static content: FAQs, policies, product docs.
MCP Server — let agents call external tools and live APIs. Best for real-time actions: order lookups, CRM queries, booking systems.
You can attach both to the same chatbot. See the Knowledge Bases guide for KB setup.
For the full API reference — including all CRUD endpoints, auth types, connection testing, tool allowlists, and how to wire MCP tools into LLM_AGENT flow actions — see the dedicated guide:
Use the API_CALL flow action to make outbound HTTP requests to your systems from within any conversation state. See the dedicated guide for full examples, variable substitution, response access, and backend setup.