Four HTTP surfaces, each opened by its own bearer token. Every endpoint here is read from the code that serves it, so the field names on this page are the field names you get back.
Base URLhttps://magizai.com
Getting started
Every surface speaks JSON over HTTPS and expects an Accept: application/json header. Send your token in the Authorization header, and read the status code before the body: a rejected request always carries a message field explaining itself.
JSON only
Requests and responses are JSON. The one exception is the widget streaming endpoint, which returns Server-Sent Events.
Workspace scoped
A token only ever reaches the workspace it was minted in. Asking for a chatbot or conversation owned by another account returns 404, never another workspace data.
Stateless
No cookies, no CSRF token, no session. Each request carries its own credentials, so the same call works from a server, a phone app or a cron job.
Tokens are Laravel Sanctum bearer tokens. Each one carries an ability that decides which surface it opens, and that ability is checked on every request.
Created in the dashboard under Settings, in the Rest API tokens panel. Name it, copy the value once (it is shown only then), and use it for the v1 endpoints. An account may hold up to 20, and revoking one takes effect immediately.
ability: api
Portal token
Minted by posting a dashboard email and password to the portal login endpoint. Only an owner or admin of a workspace that has the white-label portal switched on can obtain one.
ability: portal
Agent token
Minted by posting an email and password to the agent login endpoint. Owners, admins and agents may sign in; a read-only viewer seat is refused. The apps rotate the token before it lapses.
ability: agent
Widget endpoints
No token at all. The chatbot public key sits in the URL, and a visitor proves a conversation is theirs by sending the same visitor id that opened it.
The token types are not interchangeable. A token made on the Settings screen opens the v1 endpoints only: send it to a portal or agent route and you get 403, because those routes require the portal and agent abilities that a Settings token does not carry. Portal and agent tokens come from their own login endpoints.
Every token expires 30 days after it is issued. The agent apps rotate theirs through the refresh endpoint; for a server integration, mint a replacement before the old one lapses.
Errors
A failed request returns the matching HTTP status and a JSON body. Validation failures follow the Laravel shape: a readable message plus an errors object keyed by field name.
{
"message": "The message field is required.",
"errors": {
"message": ["The message field is required."]
}
}
Status
What causes it
401
The token is missing, malformed, expired or revoked.
403
The token is valid but not allowed here: the wrong ability for this surface, a role without the permission, or a suspended account or workspace.
404
The record does not exist, or it belongs to another workspace. The two cases are deliberately indistinguishable.
409
The request conflicts with the current state, for example inviting a visitor who has already left the site.
422
Validation failed, or a business rule refused the request. Read the errors object to see which field and why.
429
A rate limit or an account lockout was hit. Wait the number of seconds given in the Retry-After header.
500
Something failed on our side. The action did not complete.
502
The AI provider could not be reached. Check the key configured for the workspace.
503
A capability is not configured on this server, for example web push with no VAPID keys.
Rate limits
Limits are set per route and every endpoint below states its own. On authenticated routes the count is per signed-in user; on public routes it is per IP address.
A throttled response carries the usual headers, so a rejection tells you exactly how long to wait.
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 30
X-RateLimit-Remaining: 0
Retry-After: 41
Endpoints marked "No route limit" carry no throttle of their own. They are still bound by your plan monthly message allowance, so poll them at a sensible interval rather than in a tight loop.
REST API (v1)
The general-purpose integration API. Read your chatbots and conversations, add knowledge, and send a visitor message to get the AI reply back in a single JSON response. Authenticated with a token you create on the Settings screen.
Base path/api/v1·7 endpoints
GET/api/v1/me
Returns the user the token belongs to, and their workspace.
Adds a text or question-and-answer document to a chatbot and trains it immediately.
Auth Bearer token (api)Role abilitymanage-contentRate limit No route limit
Training runs inside the request rather than on a queue, so the call blocks until the document is indexed. Expect several seconds for a long document.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
title
string
Required
A name for the document. Up to 200 characters.
content
string
Required
The document text.
type
string
Optional
text or qa. Defaults to text.
Request
curl -X POST https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"title": "Refund policy",
"type": "text",
"content": "We refund any order within 30 days of delivery. Ship it back with the original packing slip and we credit the original payment method within five working days."
}'
The token is valid, but the user role does not grant this action.
404
No such record in this workspace.
422
A field failed validation. The errors object names it.
422
The document was saved but could not be trained. The response carries its id and status so you can retry training instead of uploading again.
POST/api/v1/chatbots/{key}/messages
Sends a visitor message and returns the AI reply in one response, without streaming.
Auth Bearer token (api)Role abilityhandle-conversationsRate limit No route limit
The reply is generated in full before the response is sent. For tokens as they arrive, use the widget streaming endpoint instead. When a human has taken the conversation over, reply is null and note explains why.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
message
string
Required
The visitor message. Up to 4000 characters, and it cannot be only whitespace.
visitor_id
string
Required
The id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_id
uuid
Optional
An existing conversation to continue. Leave it out to start a new one.
meta
object
Optional
Free-form context stored on the conversation.
Request
curl -X POST https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/messages \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"visitor_id": "v_2c9a71b4e5",
"message": "How long does delivery to Dubai take?"
}'
Response
{
"conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
"status": "bot",
"reply": {
"id": 33127,
"content": "Orders to Dubai arrive in two to four working days with DHL Express. You get a tracking link by email as soon as the parcel leaves our warehouse.",
"model": "claude-haiku-4-5",
"tokens_in": 812,
"tokens_out": 41
}
}
Errors
Status
What causes it
401
No valid token was sent.
403
The token is valid, but the user role does not grant this action.
404
No such record in this workspace.
422
A field failed validation. The errors object names it.
429
The workspace has reached its monthly message limit.
502
The AI provider could not be reached. Check the key configured for the workspace.
GET/api/v1/conversations/{conversation}
Returns one conversation with its full transcript.
{
"data": {
"id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
"status": "bot",
"visitor_id": "v_2c9a71b4e5",
"messages": [
{
"id": 33126,
"role": "visitor",
"content": "How long does delivery to Dubai take?",
"created_at": "2026-08-08T09:41:04.000000Z"
},
{
"id": 33127,
"role": "assistant",
"content": "Orders to Dubai arrive in two to four working days with DHL Express.",
"created_at": "2026-08-08T09:41:07.000000Z"
}
]
}
}
Errors
Status
What causes it
401
No valid token was sent.
403
The account or the workspace has been suspended.
404
No such record in this workspace.
Portal API
The tenant API behind the white-label portal a customer can host on their own domain. It manages chatbots, knowledge, provider keys, usage and the embed snippet. Data and AI stay on the platform, and a stored provider key is never sent back to the browser.
Base path/api/portal·14 endpoints
POST/api/portal/login
Exchanges a dashboard email and password for a portal bearer token.
Auth None, publicRate limit 10 requests every 1 min, per IP address
Failures are deliberately vague: a wrong password, an unknown address, a portal that is switched off and an insufficient role all return the same wording, so the endpoint cannot be used to discover which accounts exist. Attempts share one lockout counter with the web sign-in form.
Parameters
Parameter
Type
Required
Description
email
string
Required
The email address of a dashboard user. Up to 255 characters.
The email or password was wrong. The wording is the same whether or not the address exists.
403
The portal is switched off for this workspace, the workspace is suspended, or the user is not an owner or admin. Worded exactly like a wrong password, on purpose.
422
A field failed validation. The errors object names it.
429
Too many attempts, from the route limit or the shared account lockout. Retry-After says how long to wait.
POST/api/portal/logout
Revokes the portal token used to make the call.
Auth Bearer token (portal)Rate limit No route limit
{
"data": {
"public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
"name": "Support bot",
"role": "support",
"provider": "claude",
"model": "claude-haiku-4-5",
"is_active": true,
"knowledge_sources": 14,
"conversations": 67,
"persona": "Warm, direct, never oversells.",
"instructions": "Always quote delivery times from the shipping table.",
"welcome_message": "Hi! How can I help you today?",
"branding": {
"primary_color": "#4f46e5",
"launcher_text": "Chat with us",
"position": "right",
"theme": "minimal",
"logo_url": null,
"avatar_url": null,
"title": "Support bot",
"subtitle": "We typically reply in a few seconds",
"layout": "classic",
"launcher": "bubble",
"quick_replies": [],
"agent_avatars": [],
"composer_style": "full",
"sound": true,
"screen_share": false,
"copilot": false,
"auto_actions": true,
"copilot_use_profile": false,
"copilot_autostart": true,
"live_visitors": true,
"behavior_tracking": false,
"recommend_mode": "reactive",
"proactive": {
"enabled": false,
"message": "Hi! Anything I can help you find?",
"delay": 20,
"scroll": 0,
"exit_intent": false,
"url_contains": "",
"frequency": "session"
}
}
}
}
Errors
Status
What causes it
401
No valid token was sent.
403
The account or the workspace has been suspended.
404
No such record in this workspace.
PUT/api/portal/chatbots/{key}
Updates a chatbot content and widget appearance.
Auth Bearer token (portal)Role abilitymanage-chatbotsRate limit No route limit
name is required on every call. Branding fields are merged over what is stored, so sending only primary_color leaves the rest untouched, and an empty welcome_message resets it to the default greeting. The AI provider and model cannot be changed here.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
name
string
Required
The chatbot name. Up to 120 characters.
persona
string
Optional
How the assistant should sound. Up to 2000 characters.
instructions
string
Optional
Standing instructions for the assistant. Up to 4000 characters.
welcome_message
string
Optional
The greeting shown when the chat opens. Up to 300 characters; empty resets it to the default.
is_active
boolean
Optional
Whether the chatbot answers. Leave it out to keep the current setting.
primary_color
string
Optional
Widget accent colour as a hex value. Up to 9 characters.
Adds a text note, a question-and-answer pair, or a URL to crawl.
Auth Bearer token (portal)Role abilitymanage-contentRate limit No route limit
Which fields are required depends on type: content for text, question and answer for qa, source_url for url. The source is created straight away with status pending and indexed in the background, so poll the list endpoint to watch it turn ready.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
type
string
Required
text, qa or url. It decides which of the fields below are required.
title
string
Optional
A name for the source. Left out, it falls back to a sensible default for the type.
content
string
Optional
Required when type is text. The note body, up to 1,000,000 characters.
question
string
Optional
Required when type is qa. Up to 2000 characters.
answer
string
Optional
Required when type is qa. Up to 50,000 characters.
source_url
url
Optional
Required when type is url. The page to crawl, up to 2048 characters.
Request
curl -X POST https://magizai.com/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge \
-H "Authorization: Bearer $PORTAL_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"type": "qa",
"title": "Weekend delivery",
"question": "Do you deliver on Saturdays?",
"answer": "Yes. Saturday delivery is available in Dubai and Abu Dhabi at no extra cost."
}'
The workspace has no chatbot yet, so there is no snippet to return.
Agent app API
The API behind the agent mobile and desktop apps. It works the inbox: read conversations, reply, take over, resolve, tag, use AI assist, watch live visitors and register a device for push. Every action runs the same tenant logic as the web inbox, so behaviour matches exactly.
Base path/api/agent·32 endpoints
POST/api/agent/login
Exchanges an email and password for an agent bearer token.
Auth None, publicRate limit 10 requests every 1 min, per IP address
Only owners, admins and agents may sign in here. A viewer seat is refused, as is any account whose workspace is suspended. Attempts share one lockout counter with the web sign-in form and the portal API.
Parameters
Parameter
Type
Required
Description
email
string
Required
The email address of a dashboard user. Up to 255 characters.
password
string
Required
That user dashboard password.
device_name
string
Optional
A label for this device, shown beside the token. Up to 120 characters.
The email or password was wrong. The wording is the same whether or not the address exists.
403
This account cannot handle conversations, or its workspace is unavailable.
422
A field failed validation. The errors object names it.
429
Too many attempts, from the route limit or the shared account lockout. Retry-After says how long to wait.
POST/api/agent/refresh
Exchanges a still-valid agent token for a fresh one.
Auth Bearer token (agent)Rate limit 6 requests every 60 min, per signed-in user
Rotate once the token is past half its life. The old token is left to lapse on its own rather than being revoked, so a response lost in transit never signs a device out.
Authorises a realtime channel subscription for an app that holds a token instead of a session cookie.
Auth Bearer token (agent)Rate limit No route limit
Laravel own broadcasting endpoint expects a session cookie, which the apps do not have. This is the same authorisation logic, reached with a bearer token.
Returns the inbox feed: the conversation list, unread counts and section totals.
Auth Bearer token (agent)Rate limit No route limit
One response carries at most 60 rows, while groups counts the whole inbox, so use filter to reach the rest of a section. Passing conversation returns that thread in active and marks it read.
Parameters
Parameter
Type
Required
Description
filter
string
Optional
Query. Narrow the list: all, waiting, mine, team, ai, human or resolved. Defaults to all.
conversation
uuid
Optional
Query. Open this conversation, return it in active and mark it read.
Returns one conversation in full, with its transcript, visitor profile, tags, notes and events.
Auth Bearer token (agent)Rate limit No route limit
This is the inbox endpoint with the conversation pre-selected, so the body has the same shape and the requested thread arrives in active. An id that does not exist in this workspace is not an error: you still get 200, with active set to null. Opening a conversation marks it read.
Sends an agent reply and delivers it on whichever channel the conversation is running.
Auth Bearer token (agent)Role abilityhandle-conversationsRate limit No route limit
Sending a reply takes the conversation over automatically. Pass client_id from an offline outbox to make retries safe: a repeat with the same id returns the message already created and sets duplicate to true instead of sending a second one.
Parameters
Parameter
Type
Required
Description
conversation
uuid
Required
Path. The conversation public id, a UUID.
body
string
Required
The reply to send. Up to 4000 characters, and it cannot be only whitespace.
client_id
string
Optional
Your own id for this reply. Resending it returns the message already created instead of a second one. Up to 64 characters.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/reply \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"body": "I have opened a claim with the courier and posted a replacement today.",
"client_id": "outbox-2026-08-08-0007"
}'
Response
{
"message": {
"id": 33131,
"role": "agent",
"content": "I have opened a claim with the courier and posted a replacement today.",
"at": "10:47 AM"
}
}
Errors
Status
What causes it
401
No valid token was sent.
403
The token is valid, but the user role does not grant this action.
404
No such record in this workspace.
422
The reply was only whitespace.
422
A field failed validation. The errors object names it.
{
"canned": [
{
"id": 19,
"title": "Courier claim opened",
"shortcut": "/claim",
"body": "I have opened a claim with the courier. You will hear from us within one working day."
}
]
}
Errors
Status
What causes it
401
No valid token was sent.
403
The account or the workspace has been suspended.
POST/api/agent/canned/{canned}/used
Records that a canned reply was inserted, so the ordering keeps learning.
Auth Bearer token (agent)Role abilityhandle-conversationsRate limit No route limit
An agent may only mark a reply used if it is shared or their own.
Returns the visitor Shopify orders and Stripe subscription for the customer panel.
Auth Bearer token (agent)Rate limit No route limit
Both integrations degrade instead of failing. connected is false when the workspace has not connected that service; shopify.orders is then an empty array and stripe.data is null. stripe.data also comes back as {"found": false} when Stripe is connected but no customer matches the visitor email.
Drafts a reply for the agent, grounded in the chatbot knowledge.
Auth Bearer token (agent)Role abilityhandle-conversationsRate limit 30 requests every 1 min, per signed-in user
Costs one AI call. When there is nothing to answer yet, or no provider key is configured, the call still returns 200 with suggestion set to null. Keep the returned id so you can report the outcome.
Parameters
Parameter
Type
Required
Description
conversation
uuid
Required
Path. The conversation public id, a UUID.
draft
string
Optional
What the agent has typed so far, so the suggestion builds on it. Up to 4000 characters.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/suggest \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "draft": "tell her the claim is open" }'
Response
{
"id": 1204,
"suggestion": "I have opened a claim with the courier for order #8812 and posted a replacement today. You will get a new tracking link by email within the hour."
}
Errors
Status
What causes it
401
No valid token was sent.
403
The token is valid, but the user role does not grant this action.
404
No such record in this workspace.
422
A field failed validation. The errors object names it.
{
"summary": "Replacement for order 8812 never arrived; courier shows delivered. Claim opened, replacement posted.",
"summary_at": "a few seconds ago"
}
Errors
Status
What causes it
401
No valid token was sent.
403
The token is valid, but the user role does not grant this action.
404
No such record in this workspace.
422
No summary could be generated right now.
429
The route limit for this user was hit.
POST/api/agent/suggestion/{suggestion}/outcome
Records what the agent did with an AI suggestion.
Auth Bearer token (agent)Role abilityhandle-conversationsRate limit 60 requests every 1 min, per signed-in user
Report generated, inserted, edited or dismissed, so assist quality stays measurable.
The token is valid, but the user role does not grant this action.
404
No suggestion with that id in this workspace.
422
A field failed validation. The errors object names it.
429
The route limit for this user was hit.
GET/api/agent/visitors
Lists everyone on the workspace sites right now, including people who never opened the chat.
Auth Bearer token (agent)Rate limit No route limit
enabled tells you whether any active chatbot has live visitors switched on. poll_seconds is the interval the server wants you to use, so read it rather than hard-coding one.
Parameters
Parameter
Type
Required
Description
limit
integer
Optional
Query. How many visitors to return. Clamped between 1 and 200; defaults to 100.
Starts a chat with a browsing visitor by sending them the first message.
Auth Bearer token (agent)Rate limit 30 requests every 1 min, per signed-in user
Creates a conversation when the visitor has none, marks it human-handled so the AI does not talk over you, and returns 201 in that case; a visitor with an open chat gets 200. If no chat window is open, the line reaches them on their next heartbeat.
Parameters
Parameter
Type
Required
Description
visitor
string
Required
Path. The visitor id from the live visitors list. Trimmed to 100 characters.
message
string
Required
The opening line to send. Up to 2000 characters, and it cannot be only whitespace.
chatbot_id
integer
Optional
Send from this chatbot. Left out, the visitor own chatbot is preferred, then any active one.
Request
curl -X POST https://magizai.com/api/agent/visitors/v_2c9a71b4e5/invite \
-H "Authorization: Bearer $AGENT_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "message": "Hi Nadia — I can see order 8812 on your screen. Want me to check it?" }'
Response
{
"conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
"created": true,
"delivery_within_seconds": 25,
"message": {
"id": 33140,
"role": "agent",
"content": "Hi Nadia — I can see order 8812 on your screen. Want me to check it?",
"at": "10:52 AM"
}
}
Errors
Status
What causes it
401
No valid token was sent.
403
The account or the workspace has been suspended.
404
The visitor id was empty after trimming.
409
That visitor is no longer on the site.
422
The workspace has no active chatbot to send from.
429
The route limit for this user was hit.
500
The chat could not be started. Nothing was saved, so it is safe to try again.
GET/api/agent/push/vapid
Returns the public key a device needs before it can subscribe to push.
Auth Bearer token (agent)Rate limit No route limit
configured is false on a server where push has never been set up, which lets an app explain the situation instead of failing at the subscribe step.
Auth Bearer token (agent)Rate limit 20 requests every 1 min, per signed-in user
Upserts on the endpoint, because browsers reissue a subscription whenever the push service rotates it. Re-sending an existing endpoint updates the record rather than creating a second one.
Parameters
Parameter
Type
Required
Description
endpoint
url
Required
The push endpoint issued by the browser. Must be an https URL, up to 2048 characters.
keys
object
Required
The subscription key pair from the browser.
keys.p256dh
string
Required
The p256dh key from the browser subscription. Up to 255 characters.
keys.auth
string
Required
The auth secret from the browser subscription. Up to 255 characters.
device_name
string
Optional
A label for this device, shown beside the token. Up to 120 characters.
Updates this agent alert preferences and availability.
Auth Bearer token (agent)Rate limit No route limit
A partial update: only the fields you send change, and the events map is merged rather than replaced, so an older app version cannot wipe a setting it does not know about. Unknown event keys are ignored.
Parameters
Parameter
Type
Required
Description
push_enabled
boolean
Optional
Master switch for push alerts on this account.
sound_enabled
boolean
Optional
Whether alerts play a sound.
vibrate_enabled
boolean
Optional
Whether alerts vibrate the device.
email_enabled
boolean
Optional
Whether alerts are also sent by email.
events
object
Optional
Per-event settings, keyed by event: visitor_arrived, chat_started, visitor_message, handoff_requested, sla_breach. Merged with what is stored.
events.*.push
boolean
Optional
Whether this event sends a push. Required for each event you include.
events.*.sound
string
Optional
Sound name for this event, or null for the default. Up to 24 characters.
sound_pack
string
Optional
Name of the sound pack. Up to 24 characters.
volume
integer
Optional
Alert volume from 0 to 100.
quiet_hours_start
string
Optional
Start of quiet hours as HH:MM, read in the agent own timezone.
quiet_hours_end
string
Optional
End of quiet hours as HH:MM. It must be sent together with the start.
quiet_hours_tz
string
Optional
Timezone the quiet hours are read in, for example Asia/Dubai. Up to 64 characters.
dnd_minutes
integer
Optional
Silence alerts for this many minutes, from 0 to 1440. Send 0 to clear.
chatbot_filter
array
Optional
Only alert on these chatbot ids. Ids outside the workspace are dropped, and an empty result clears the filter.
only_my_conversations
boolean
Optional
Only alert on conversations assigned to this agent.
Quiet hours need both a start and an end time; half a window would do nothing.
422
A field failed validation. The errors object names it.
500
The settings could not be saved.
Widget endpoints
The public endpoints the embed script calls from your visitors browsers. They are documented so you can debug an install or build a custom chat front end. They are not an integration API and none of them accept a token.
Base path/widget/{key}·7 endpoints
GET/widget/{key}/config
Returns the public configuration for a chatbot: branding, greeting, pre-chat form and realtime connection details.
Auth None, publicRate limit 60 requests every 1 min, per IP address
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
{
"public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
"name": "Support bot",
"welcome_message": "Hi! How can I help you today?",
"human_handoff_enabled": true,
"branding": {
"primary_color": "#4f46e5",
"launcher_text": "Chat with us",
"position": "right",
"theme": "minimal",
"logo_url": null,
"avatar_url": null,
"title": "Support bot",
"subtitle": "We typically reply in a few seconds",
"layout": "classic",
"launcher": "bubble",
"quick_replies": [],
"agent_avatars": [],
"composer_style": "full",
"sound": true,
"screen_share": false,
"copilot": false,
"auto_actions": true,
"copilot_use_profile": false,
"copilot_autostart": true,
"live_visitors": true,
"behavior_tracking": false,
"recommend_mode": "reactive",
"proactive": {
"enabled": false,
"message": "Hi! Anything I can help you find?",
"delay": 20,
"scroll": 0,
"exit_intent": false,
"url_contains": "",
"frequency": "session"
}
},
"powered_by": "MagizAI",
"powered_by_url": "https://magizai.com",
"pre_chat_form": {
"enabled": true,
"greeting": "Before we start, please introduce yourself.",
"fields": {
"name": { "enabled": true, "required": false },
"email": { "enabled": true, "required": true },
"phone": { "enabled": false, "required": false }
}
},
"realtime": {
"key": "reverbappkey",
"host": "realtime.acme.test",
"port": 443,
"scheme": "https"
}
}
Errors
Status
What causes it
404
No active chatbot has that public key. An inactive chatbot answers the same way.
429
The route limit for this IP address was hit.
POST/widget/{key}/boot
Opens or resumes a visitor conversation and returns the transcript so far.
Auth None, publicRate limit 30 requests every 1 min, per IP address
Pass a conversation_id to resume. If it does not match the visitor id you send, or that conversation was closed, a new one is opened rather than the call failing.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
visitor_id
string
Required
The id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_id
uuid
Optional
An existing conversation to continue. Leave it out to start a new one.
meta
object
Optional
Context about the visitor and page. meta.visitor may carry name, email and phone from your pre-chat form.
identity
string
Optional
A signed identity token from your own backend. It is verified before anything in it is trusted. Up to 4000 characters.
{
"conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
"status": "bot",
"handoff_state": "bot_active",
"wait_remaining": null,
"messages": [
{
"id": 33126,
"role": "visitor",
"content": "I still have not received the replacement.",
"at": "2026-08-08T10:41:04+00:00"
},
{
"id": 33127,
"role": "assistant",
"content": "Let me check that order for you.",
"at": "2026-08-08T10:41:07+00:00"
}
]
}
Errors
Status
What causes it
404
No active chatbot has that public key. An inactive chatbot answers the same way.
422
A field failed validation. The errors object names it.
429
The route limit for this IP address was hit.
POST/widget/{key}/stream
Sends a visitor message and streams the AI reply back as Server-Sent Events.
Auth None, publicRate limit 20 requests every 1 min, per IP address
The response is a text/event-stream, not JSON. Events arrive in order: meta first, then any number of delta events, optionally recommendations, and finally done or error. A rejection before streaming starts is a normal JSON error response.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
visitor_id
string
Required
The id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
message
string
Required
The visitor message. Up to 4000 characters, and it cannot be only whitespace.
conversation_id
uuid
Optional
An existing conversation to continue. Leave it out to start a new one.
meta
object
Optional
Context about the visitor and page. meta.visitor may carry name, email and phone from your pre-chat form.
identity
string
Optional
A signed identity token from your own backend. It is verified before anything in it is trusted. Up to 4000 characters.
Request
curl -N -X POST https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/stream \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-d '{
"visitor_id": "v_2c9a71b4e5",
"conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
"message": "Where is my replacement?"
}'
Response
event: meta
data: {"conversation_id":"6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91","visitor_message_id":33128,"status":"bot"}
event: delta
data: {"delta":"Your replacement "}
event: delta
data: {"delta":"was posted this morning."}
event: recommendations
data: {"products":[{"id":41,"name":"Express delivery","price":"AED 25.00","currency":"AED","url":"https://acme.test/express","buy_url":"https://acme.test/express","image_url":null,"description":"Next-working-day delivery across the UAE.","in_stock":true}]}
event: done
data: {"message_id":33129,"source":"ai","sources":[{"title":"Shipping policy","url":"https://acme.test/shipping"}]}
Errors
Status
What causes it
404
No active chatbot has that public key. An inactive chatbot answers the same way.
422
The message was only whitespace.
422
A field failed validation. The errors object names it.
429
The route limit for this IP address was hit.
POST/widget/{key}/chat/reset
Closes the visitor current conversation so the widget can start a clean one.
Auth None, publicRate limit 30 requests every 1 min, per IP address
Idempotent and ownership-checked. It closes the conversation on the server; the widget then boots a fresh one, which is what clears the context.
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
visitor_id
string
Required
The id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_id
uuid
Required
The conversation to close. It must belong to the visitor id you send.
{
"status": "agent",
"handoff_state": "human_connected",
"wait_remaining": null,
"messages": [
{
"id": 33131,
"role": "agent",
"content": "I have opened a claim with the courier and posted a replacement today.",
"at": "2026-08-08T10:47:20+00:00"
}
]
}
Errors
Status
What causes it
404
No conversation with that id for this chatbot and visitor id.
422
A field failed validation. The errors object names it.
Records a satisfaction score for the whole conversation.
Auth None, publicRate limit 10 requests every 1 min, per IP address
Parameters
Parameter
Type
Required
Description
key
string
Required
Path. The chatbot public key, the same value used in the embed snippet.
conversationId
uuid
Required
Path. The conversation public id, a UUID.
visitor_id
string
Required
The id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
score
integer
Required
Satisfaction score from 1 to 5.
comment
string
Optional
Free-text comment. Up to 2000 characters.
Request
curl -X POST https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/csat \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"visitor_id": "v_2c9a71b4e5",
"score": 5,
"comment": "Sorted in two minutes."
}'
Response
{
"ok": true
}
Errors
Status
What causes it
404
No conversation with that id for this chatbot and visitor id.
422
A field failed validation. The errors object names it.
429
The route limit for this IP address was hit.
Widget endpoints not documented here
These exist and the embed script uses them, but they are internal to the widget rather than something to call yourself. They are listed so you know they were left out on purpose.
Method
Endpoint
Why
POST
/widget/{key}/upload
Multipart file upload, bound to the widget attachment flow and its storage rules.
POST
/widget/{key}/request-human
Offline handoff intake. It sends email and WhatsApp alerts to the workspace, so it stays behind the widget own flow.
POST
/widget/{key}/conversions
Conversion beacon for the reporting pipeline, meaningful only alongside the widget tracking script.
POST
/widget/{key}/track
Behaviour beacon for page, product and cart events. Opt-in per chatbot and shaped entirely by the widget.
POST
/widget/{key}/presence
Live-visitor heartbeat. Its timing is tied to the widget beacon interval.
POST
/widget/{key}/assist
Co-pilot guidance. The payload is a snapshot of the visitor page produced by the widget.
Need something that is not here?
Tell us what you are building and we will point you at the right endpoint, or add one.