MagizAI
Developers

Build on MagizAI

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 URL https://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.

curl https://magizai.com/api/v1/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Authentication

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.

Authorization: Bearer <token>
Accept: application/json
REST API token

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.

Auth Bearer token (api) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/v1/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
Response
{
  "user": {
    "id": 12,
    "name": "Amelia Fox",
    "email": "[email protected]",
    "role": "owner"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "slug": "acme-ltd",
    "plan": "pro"
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/v1/chatbots

Lists every chatbot in the workspace.

Auth Bearer token (api) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/v1/chatbots \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": [
    {
      "id": 7,
      "public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
      "name": "Support bot",
      "provider": "claude",
      "model": "claude-haiku-4-5",
      "is_active": true
    }
  ]
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/v1/chatbots/{key}

Returns one chatbot, including its widget branding and how many knowledge sources it holds.

Auth Bearer token (api) Rate limit No route limit
Parameters
Parameter Type Required Description
key string Required Path. The chatbot public key, the same value used in the embed snippet.
Request
curl https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": {
    "public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
    "name": "Support bot",
    "provider": "claude",
    "model": "claude-haiku-4-5",
    "is_active": true,
    "knowledge_sources": 14,
    "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.
GET /api/v1/chatbots/{key}/conversations

Lists a chatbot conversations, most recent activity first, as a paginated result.

Auth Bearer token (api) Rate limit No route limit
Parameters
Parameter Type Required Description
key string Required Path. The chatbot public key, the same value used in the embed snippet.
per_page integer Optional Query. Rows per page. Defaults to 20 and is capped at 100.
Request
curl "https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?per_page=2" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
Response
{
  "current_page": 1,
  "data": [
    {
      "id": 4821,
      "public_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
      "status": "bot",
      "visitor_id": "v_2c9a71b4e5",
      "last_message_at": "2026-08-08T09:41:12.000000Z"
    },
    {
      "id": 4820,
      "public_id": "1d3f92ac-77b1-4a0d-8c6e-2f5a9b4c1d70",
      "status": "closed",
      "visitor_id": "v_71ad03f9c2",
      "last_message_at": "2026-08-08T08:02:55.000000Z"
    }
  ],
  "first_page_url": "https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=1",
  "from": 1,
  "last_page": 34,
  "last_page_url": "https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=34",
  "next_page_url": "https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=2",
  "path": "https://magizai.com/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations",
  "per_page": 2,
  "prev_page_url": null,
  "to": 2,
  "total": 67
}
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.
POST /api/v1/chatbots/{key}/knowledge

Adds a text or question-and-answer document to a chatbot and trains it immediately.

Auth Bearer token (api) Role ability manage-content Rate 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."
      }'
Response
{
  "data": {
    "id": 918,
    "title": "Refund policy",
    "type": "text",
    "status": "ready",
    "chunk_count": 3
  }
}
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.
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 ability handle-conversations Rate 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.

Auth Bearer token (api) Rate limit No route limit
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl https://magizai.com/api/v1/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"
Response
{
  "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, public Rate 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.
password string Required That user dashboard password.
Request
curl -X POST https://magizai.com/api/portal/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "email": "[email protected]",
        "password": "correct-horse-battery-staple"
      }'
Response
{
  "token": "17|Ck2Ft9pQvYb3xLmR8sJd0aWnZeH6uT4gPqK1oI5c",
  "user": {
    "name": "Amelia Fox",
    "email": "[email protected]",
    "role": "owner"
  },
  "company": {
    "name": "Acme Ltd",
    "plan": "pro"
  },
  "brand": {
    "name": "Acme Support",
    "powered_by": "MagizAI",
    "logo_url": "https://cdn.acme.test/logo.svg"
  }
}
Errors
Status What causes it
401 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
Parameters

This endpoint takes no parameters.

Request
curl -X POST https://magizai.com/api/portal/logout \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "message": "Signed out."
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/portal/me

Returns the signed-in user, the workspace, its white-label brand, plan limits and this month usage.

Auth Bearer token (portal) Rate limit No route limit

monthly_message_limit is null on an unlimited plan, and usage_percent is null with it.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/portal/me \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "user": {
    "name": "Amelia Fox",
    "email": "[email protected]",
    "role": "owner"
  },
  "company": {
    "name": "Acme Ltd",
    "plan": "pro"
  },
  "brand": {
    "name": "Acme Support",
    "powered_by": "MagizAI",
    "logo_url": "https://cdn.acme.test/logo.svg"
  },
  "limits": {
    "plan": "Pro",
    "monthly_message_limit": 10000,
    "chatbot_limit": 5,
    "agent_seats": 10
  },
  "usage": {
    "messages_used": 3142,
    "message_limit": 10000,
    "usage_percent": 31,
    "chatbots": 2
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/portal/chatbots

Lists every chatbot in the workspace with its knowledge and conversation counts.

Auth Bearer token (portal) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/portal/chatbots \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "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
    }
  ]
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/portal/chatbots/{key}

Returns one chatbot with its persona, instructions, welcome message and branding.

Auth Bearer token (portal) Rate limit No route limit
Parameters
Parameter Type Required Description
key string Required Path. The chatbot public key, the same value used in the embed snippet.
Request
curl https://magizai.com/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "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 ability manage-chatbots Rate 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.
launcher_text string Optional Label on the chat launcher. Up to 40 characters.
position string Optional Which side the widget sits on: left or right.
theme string Optional Widget theme: minimal, ocean, emerald, midnight, sunset, crisp, violet, rose, slate or forest.
Request
curl -X PUT https://magizai.com/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "name": "Support bot",
        "welcome_message": "Hi! Ask me anything about your order.",
        "primary_color": "#0a7d5f",
        "position": "right",
        "theme": "emerald",
        "is_active": true
      }'
Response
{
  "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! Ask me anything about your order.",
    "branding": {
      "primary_color": "#0a7d5f",
      "launcher_text": "Chat with us",
      "position": "right",
      "theme": "emerald"
    }
  }
}
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.
GET /api/portal/chatbots/{key}/knowledge

Lists a chatbot knowledge sources and their training status.

Auth Bearer token (portal) Rate limit No route limit

Only top-level sources are listed. Pages discovered while crawling a URL are children of that source and do not appear separately.

Parameters
Parameter Type Required Description
key string Required Path. The chatbot public key, the same value used in the embed snippet.
Request
curl https://magizai.com/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": [
    {
      "id": 918,
      "type": "text",
      "title": "Refund policy",
      "source_url": null,
      "status": "ready",
      "chunk_count": 3,
      "created_at": "2026-08-08T09:12:44+00:00"
    },
    {
      "id": 902,
      "type": "url",
      "title": "acme.test",
      "source_url": "https://acme.test/shipping",
      "status": "processing",
      "chunk_count": 0,
      "created_at": "2026-08-07T16:30:02+00:00"
    }
  ]
}
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.
POST /api/portal/chatbots/{key}/knowledge

Adds a text note, a question-and-answer pair, or a URL to crawl.

Auth Bearer token (portal) Role ability manage-content Rate 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."
      }'
Response
{
  "data": {
    "id": 919,
    "type": "qa",
    "title": "Weekend delivery",
    "source_url": null,
    "status": "pending",
    "chunk_count": 0,
    "created_at": "2026-08-08T10:04:18+00:00"
  }
}
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.
DELETE /api/portal/chatbots/{key}/knowledge/{source}

Removes a knowledge source, its stored file and everything indexed from it.

Auth Bearer token (portal) Role ability manage-content Rate limit No route limit
Parameters
Parameter Type Required Description
key string Required Path. The chatbot public key, the same value used in the embed snippet.
source integer Required Path. The knowledge source id.
Request
curl -X DELETE https://magizai.com/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge/919 \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "message": "Knowledge source removed."
}
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.
GET /api/portal/keys

Lists every AI provider and whether this workspace has its own key on file.

Auth Bearer token (portal) Rate limit No route limit

A stored key is never returned, only its last four characters and whether one exists.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/portal/keys \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": [
    { "provider": "claude",     "label": "Anthropic Claude", "last_four": "9f2c", "configured": true },
    { "provider": "openai",     "label": "OpenAI",           "last_four": null,   "configured": false },
    { "provider": "gemini",     "label": "Google Gemini",    "last_four": null,   "configured": false },
    { "provider": "deepseek",   "label": "DeepSeek",         "last_four": null,   "configured": false },
    { "provider": "kimi",       "label": "Moonshot Kimi",    "last_four": null,   "configured": false },
    { "provider": "groq",       "label": "Groq (Llama)",     "last_four": null,   "configured": false },
    { "provider": "mistral",    "label": "Mistral",          "last_four": null,   "configured": false },
    { "provider": "openrouter", "label": "OpenRouter",       "last_four": null,   "configured": false }
  ]
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
PUT /api/portal/keys/{provider}

Stores or replaces the workspace key for one AI provider.

Auth Bearer token (portal) Role ability manage-workspace Rate limit No route limit
Parameters
Parameter Type Required Description
provider string Required Path. Provider slug: claude, openai, gemini, deepseek, kimi, groq, mistral or openrouter.
api_key string Required The provider API key. Stored encrypted and never returned. Up to 300 characters.
Request
curl -X PUT https://magizai.com/api/portal/keys/openai \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "api_key": "sk-proj-0f4c8b2e6a1d7f3c9b5e0a2d" }'
Response
{
  "data": {
    "provider": "openai",
    "last_four": "a2d0",
    "configured": true
  }
}
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.
422 That provider slug is not recognised.
422 A field failed validation. The errors object names it.
DELETE /api/portal/keys/{provider}

Removes the workspace key for one AI provider.

Auth Bearer token (portal) Role ability manage-workspace Rate limit No route limit

Idempotent. Deleting a provider that has no key still returns 200, with a message saying nothing was set.

Parameters
Parameter Type Required Description
provider string Required Path. Provider slug: claude, openai, gemini, deepseek, kimi, groq, mistral or openrouter.
Request
curl -X DELETE https://magizai.com/api/portal/keys/openai \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "message": "API key removed."
}
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.
422 That provider slug is not recognised.
GET /api/portal/analytics

Returns this month conversation, message, token and cost totals for the workspace.

Auth Bearer token (portal) Rate limit No route limit

cost is in whole currency units, converted from the micro-cent totals kept internally. The period always starts on the first day of the current month.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/portal/analytics \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": {
    "period": "month",
    "since": "2026-08-01T00:00:00+00:00",
    "conversations": 412,
    "messages": {
      "ai_replies": 1904,
      "human_replies": 233,
      "visitor_messages": 2088,
      "total": 4225
    },
    "tokens": 1874320,
    "cost": 4.216874,
    "messages_used": 3142
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/portal/widget-snippet

Returns the ready-to-paste embed script tag for the workspace chatbot.

Auth Bearer token (portal) Rate limit No route limit

Picks the first active chatbot, falling back to the most recently created one.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/portal/widget-snippet \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"
Response
{
  "data": {
    "public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
    "snippet": "<script src=\"https://magizai.com/widget.js\" data-key=\"cv_9f2a4c7e1b6d3a8f5c0e2b4d\" defer></script>"
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
404 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, public Rate 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.
Request
curl -X POST https://magizai.com/api/agent/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "email": "[email protected]",
        "password": "correct-horse-battery-staple",
        "device_name": "Sara iPhone 15"
      }'
Response
{
  "token": "42|Yb7Kd1sQvNc3xLmR8sJd0aWnZeH6uT4gPqK1oI5c",
  "expires_at": "2026-09-07T10:14:02+00:00",
  "device_name": "Sara iPhone 15",
  "user": {
    "id": 58,
    "name": "Sara Bell",
    "email": "[email protected]",
    "role": "Agent",
    "avatar": "https://cdn.acme.test/avatars/58.png"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "plan": "pro"
  }
}
Errors
Status What causes it
401 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.

Parameters

This endpoint takes no parameters.

Request
curl -X POST https://magizai.com/api/agent/refresh \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "token": "43|Qw9Lm2tRvNc3xLmR8sJd0aWnZeH6uT4gPqK1oI5c",
  "expires_at": "2026-09-07T11:02:31+00:00",
  "device_name": "Sara iPhone 15",
  "user": {
    "id": 58,
    "name": "Sara Bell",
    "email": "[email protected]",
    "role": "Agent",
    "avatar": "https://cdn.acme.test/avatars/58.png"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "plan": "pro"
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
429 The route limit for this user was hit.
GET /api/agent/me

Returns the signed-in agent, their workspace, and when the current token expires.

Auth Bearer token (agent) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/agent/me \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "user": {
    "id": 58,
    "name": "Sara Bell",
    "email": "[email protected]",
    "role": "Agent",
    "avatar": "https://cdn.acme.test/avatars/58.png"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "plan": "pro"
  },
  "expires_at": "2026-09-07T10:14:02+00:00",
  "device_name": "Sara iPhone 15"
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/logout

Revokes the agent token used to make the call.

Auth Bearer token (agent) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl -X POST https://magizai.com/api/agent/logout \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "message": "Signed out."
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/broadcasting/auth

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.

Parameters
Parameter Type Required Description
socket_id string Required The socket id given by the realtime connection.
channel_name string Required The channel being subscribed to.
Request
curl -X POST https://magizai.com/api/agent/broadcasting/auth \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "socket_id": "812734.1904221",
        "channel_name": "private-company.3"
      }'
Response
{
  "auth": "reverbappkey:6f1c0a9b8e7d5c4b3a2f1e0d9c8b7a6f5e4d3c2b1a0f9e8d7c6b5a4f3e2d1c0b"
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
403 The token holder is not allowed on that channel.
GET /api/agent/inbox

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.
Request
curl "https://magizai.com/api/agent/inbox?filter=waiting" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "conversations": [
    {
      "id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
      "chatbot": "Support bot",
      "visitor": "Nadia Karim",
      "email": "[email protected]",
      "status": "agent",
      "channel": "website",
      "last_at": "2 minutes ago",
      "preview": "I still have not received the replacement…",
      "escalated": true,
      "unread": 2,
      "resolution": null,
      "tags": [
        { "id": 4, "name": "Delivery", "color": "#0a7d5f" }
      ],
      "group": "waiting",
      "handoff_state": "handoff_pending",
      "assigned_to": null,
      "mine": false,
      "online": true,
      "waiting_seconds": 143
    }
  ],
  "counts": {
    "all": 412,
    "ai": 301,
    "human": 74,
    "resolved": 37,
    "unread": 6
  },
  "groups": {
    "waiting": 3,
    "mine": 5,
    "team": 12,
    "ai": 355,
    "resolved": 37
  },
  "listed": 1,
  "list_limit": 60,
  "active": null
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
GET /api/agent/conversations/{conversation}

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.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91 \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "conversations": [],
  "counts": { "all": 412, "ai": 301, "human": 74, "resolved": 37, "unread": 6 },
  "groups": { "waiting": 3, "mine": 5, "team": 12, "ai": 355, "resolved": 37 },
  "listed": 0,
  "list_limit": 60,
  "active": {
    "id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
    "status": "agent",
    "resolution": null,
    "resolved_at": null,
    "handoff_requested_at": "Aug 8, 2026 · 10:41 AM",
    "escalated": true,
    "resolved_by_ai": false,
    "events": [
      { "type": "human_connected", "source": "agent", "at": "Aug 8 · 10:42 AM" }
    ],
    "tags": [
      { "id": 4, "name": "Delivery", "color": "#0a7d5f", "source": "manual" }
    ],
    "tag_suggestions": [
      { "id": 71, "name": "Refund", "confidence": 0.82, "reason": "Visitor asked for money back." }
    ],
    "visitor": "Nadia Karim",
    "chatbot": "Support bot",
    "channel": "website",
    "email": "[email protected]",
    "phone": null,
    "page": "https://acme.test/orders/8812",
    "locale": "en",
    "joined": "Aug 8, 2026",
    "msg_count": 9,
    "group": "mine",
    "handoff_state": "human_connected",
    "assigned_to": "Sara Bell",
    "mine": true,
    "online": true,
    "last_seen": "12 seconds ago",
    "waiting_seconds": null,
    "referrer": "https://www.google.com/",
    "entry_page": "https://acme.test/",
    "device": "mobile",
    "browser": "Safari",
    "os": "iOS",
    "country": "AE",
    "timezone": "Asia/Dubai",
    "page_views": 6,
    "prechat": [
      { "field": "name", "value": "Nadia Karim" },
      { "field": "email", "value": "[email protected]" }
    ],
    "prechat_greeting": "Before we start, please introduce yourself.",
    "journey": [
      { "url": "https://acme.test/orders/8812", "at": "Aug 8 · 10:38 AM" },
      { "url": "https://acme.test/", "at": null }
    ],
    "revenue_cents": 24900,
    "revenue_amount": 249.0,
    "revenue_currency": "AED",
    "revenue_label": "AED 249.00",
    "summary": "Replacement for order 8812 never arrived; courier shows delivered.",
    "summary_at": "3 minutes ago",
    "intent": "support",
    "lead_id": 233,
    "lead_status": "new",
    "messages": [
      { "id": 33126, "role": "visitor", "content": "I still have not received the replacement.", "at": "10:41 AM" },
      { "id": 33127, "role": "agent", "content": "Let me pull up the courier record now.", "at": "10:42 AM" }
    ],
    "notes": [
      { "id": 12, "body": "Courier claims delivered — opening a claim.", "author": "Sara Bell", "at": "Aug 8 · 10:44 AM" }
    ],
    "watchers": [],
    "watching": false,
    "detected_language": "en",
    "routed_by": "VIP customers",
    "blocked": false,
    "abuse_strikes": 0
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/conversations/{conversation}/reply

Sends an agent reply and delivers it on whichever channel the conversation is running.

Auth Bearer token (agent) Role ability handle-conversations Rate 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.
POST /api/agent/conversations/{conversation}/takeover

Takes the conversation from the AI and assigns it to the calling agent.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/takeover \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "status": "agent"
}
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.
POST /api/agent/conversations/{conversation}/release

Hands the conversation back to the AI.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/release \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "status": "bot"
}
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.
POST /api/agent/conversations/{conversation}/resolve

Closes the conversation as resolved.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit

A resolved conversation reopens by itself if the visitor comes back with a new message.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/resolve \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "status": "closed",
  "resolution": "resolved"
}
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.
POST /api/agent/conversations/{conversation}/reopen

Reopens a closed conversation and returns it to the AI.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/reopen \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "status": "bot"
}
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.
GET /api/agent/tags

Lists the workspace tag catalogue.

Auth Bearer token (agent) Rate limit No route limit
Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/agent/tags \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "tags": [
    { "id": 4, "name": "Delivery", "color": "#0a7d5f" },
    { "id": 5, "name": "Refund", "color": "#b4531f" }
  ]
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/conversations/{conversation}/tags

Attaches a catalogue tag to a conversation.

Auth Bearer token (agent) Rate limit No route limit

The tag must already exist in the workspace catalogue; create tags in the dashboard.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
tag_id integer Required The id of a tag already in the workspace catalogue.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/tags \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "tag_id": 4 }'
Response
{
  "attached": 4
}
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.
422 A field failed validation. The errors object names it.
DELETE /api/agent/conversations/{conversation}/tags/{tag}

Removes a tag from a conversation.

Auth Bearer token (agent) Rate limit No route limit
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
tag integer Required Path. The tag id.
Request
curl -X DELETE https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/tags/4 \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "detached": 4
}
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.
GET /api/agent/canned

Lists the canned replies this agent can use, most used first.

Auth Bearer token (agent) Rate limit No route limit

Shared replies plus this agent own, ordered by how often each has been used.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/agent/canned \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "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 ability handle-conversations Rate limit No route limit

An agent may only mark a reply used if it is shared or their own.

Parameters
Parameter Type Required Description
canned integer Required Path. The canned reply id.
Request
curl -X POST https://magizai.com/api/agent/canned/19/used \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "ok": true
}
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.
403 The canned reply belongs to another agent and is not shared.
404 No canned reply with that id in this workspace.
GET /api/agent/conversations/{conversation}/customer-context

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.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/customer-context \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "email": "[email protected]",
  "shopify": {
    "connected": true,
    "orders": [
      {
        "name": "#8812",
        "total": "249.00 AED",
        "financial_status": "paid",
        "fulfillment_status": "fulfilled",
        "created_at": "Aug 1, 2026",
        "url": "https://acme.test/account/orders/5541882"
      }
    ]
  },
  "stripe": {
    "connected": true,
    "data": {
      "found": true,
      "customer": {
        "name": "Nadia Karim",
        "email": "[email protected]"
      },
      "subscriptions": [
        {
          "status": "active",
          "plan": "Care Plus",
          "amount": "29.00 AED",
          "renews": "Sep 1, 2026"
        }
      ]
    }
  }
}
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.
POST /api/agent/conversations/{conversation}/revenue

Sets or clears the deal value attributed to a conversation.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit

Send amount as null to clear the value. Currency falls back to whatever is already on the conversation, then to USD.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
amount number Optional Deal value in whole currency units, up to 100,000,000. Send null to clear it.
currency string Optional Three-letter currency code. Falls back to the value already on the conversation, then to USD.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/revenue \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "amount": 249, "currency": "AED" }'
Response
{
  "revenue_cents": 24900,
  "revenue_amount": 249.0,
  "revenue_currency": "AED",
  "revenue_label": "AED 249.00"
}
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.
POST /api/agent/conversations/{conversation}/lead

Saves the contact details captured on a conversation as a lead.

Auth Bearer token (agent) Role ability handle-conversations Rate limit No route limit

Needs at least one of name, email or phone already captured on the conversation, otherwise there is nothing to save.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/lead \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "lead": {
    "id": 233,
    "status": "new",
    "source": "manual"
  }
}
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 name, email or phone has been captured on this conversation yet.
POST /api/agent/conversations/{conversation}/suggest

Drafts a reply for the agent, grounded in the chatbot knowledge.

Auth Bearer token (agent) Role ability handle-conversations Rate 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.
429 The route limit for this user was hit.
POST /api/agent/conversations/{conversation}/enhance

Rewrites the agent own draft for grammar or tone.

Auth Bearer token (agent) Role ability handle-conversations Rate limit 30 requests every 1 min, per signed-in user

Costs one AI call. If the model cannot improve the text, the original comes back with enhanced set to false.

Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
body string Required The draft to rewrite. Up to 4000 characters, and it cannot be only whitespace.
mode string Optional fix, professional, friendly, concise or expand. Defaults to fix.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/enhance \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "body": "claim is open, replacement sent today",
        "mode": "professional"
      }'
Response
{
  "text": "The claim is open and a replacement was posted today.",
  "enhanced": true
}
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 draft was only whitespace.
422 A field failed validation. The errors object names it.
429 The route limit for this user was hit.
POST /api/agent/conversations/{conversation}/summary

Generates a short internal summary of the conversation.

Auth Bearer token (agent) Role ability handle-conversations Rate limit 30 requests every 1 min, per signed-in user
Parameters
Parameter Type Required Description
conversation uuid Required Path. The conversation public id, a UUID.
Request
curl -X POST https://magizai.com/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/summary \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "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 ability handle-conversations Rate limit 60 requests every 1 min, per signed-in user

Report generated, inserted, edited or dismissed, so assist quality stays measurable.

Parameters
Parameter Type Required Description
suggestion integer Required Path. The id returned by the suggest endpoint.
outcome string Required generated, inserted, edited or dismissed.
Request
curl -X POST https://magizai.com/api/agent/suggestion/1204/outcome \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "outcome": "edited" }'
Response
{
  "ok": true
}
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 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.
Request
curl "https://magizai.com/api/agent/visitors?limit=50" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "visitors": [
    {
      "id": "90211",
      "visitor_id": "v_2c9a71b4e5",
      "session_token": "ps_5f1c0a9b8e7d5c4b3a2f1e0d",
      "label": "Nadia Karim",
      "short": "2C9A",
      "name": "Nadia Karim",
      "email": "[email protected]",
      "current_url": "https://acme.test/orders/8812",
      "current_title": "Order 8812",
      "entry_url": "https://acme.test/",
      "referrer": "https://www.google.com/",
      "country": "AE",
      "device": "mobile",
      "browser": "Safari",
      "os": "iOS",
      "page_views": 6,
      "seconds_on_site": 412,
      "last_seen_at": "2026-08-08T10:46:51+00:00",
      "started_at": "2026-08-08T10:39:59+00:00",
      "state": "chatting",
      "conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
      "unread": 2,
      "chatbot": "Support bot"
    }
  ],
  "counts": {
    "total": 1,
    "browsing": 0,
    "chatting": 1,
    "waiting": 0
  },
  "poll_seconds": 25,
  "enabled": true
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/visitors/{visitor}/invite

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.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/agent/push/vapid \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "configured": true,
  "public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U"
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
POST /api/agent/push/subscribe

Registers a device to receive push alerts.

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.
platform string Optional ios, android or desktop.
Request
curl -X POST https://magizai.com/api/agent/push/subscribe \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "endpoint": "https://web.push.apple.com/QK9x2m4Lp0",
        "keys": {
          "p256dh": "BJx7Qm2f0aLd9k3sVn1cRt8yUu5oWq4eZa6hGi2jKl0",
          "auth": "9fK2sQ7vN1cX3mLp"
        },
        "device_name": "Sara iPhone 15",
        "platform": "ios"
      }'
Response
{
  "ok": true,
  "id": 77,
  "devices": 2
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
422 The endpoint is not an https URL, so it cannot be a real push service.
422 A field failed validation. The errors object names it.
429 The route limit for this user was hit.
500 The device could not be registered for alerts.
DELETE /api/agent/push/subscribe

Removes this device push subscription.

Auth Bearer token (agent) Rate limit No route limit

Scoped to the caller, so a leaked endpoint cannot be used to cut off another agent alerts.

Parameters
Parameter Type Required Description
endpoint string Required The push endpoint to remove. Up to 2048 characters.
Request
curl -X DELETE https://magizai.com/api/agent/push/subscribe \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "endpoint": "https://web.push.apple.com/QK9x2m4Lp0" }'
Response
{
  "ok": true,
  "removed": 1
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
422 A field failed validation. The errors object names it.
POST /api/agent/push/test

Sends a real test alert to the calling agent own devices.

Auth Bearer token (agent) Rate limit 6 requests every 1 min, per signed-in user

Deliberately ignores quiet hours and do-not-disturb: someone asking to test delivery wants to know whether it works.

Parameters

This endpoint takes no parameters.

Request
curl -X POST https://magizai.com/api/agent/push/test \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "ok": true,
  "result": {
    "sent": 2,
    "failed": 0,
    "pruned": 0
  }
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
422 No device received the test. Allow notifications on the device and try again.
429 The route limit for this user was hit.
503 Push is not configured on this server.
GET /api/agent/settings/notifications

Returns this agent alert preferences, availability and registered devices.

Auth Bearer token (agent) Rate limit No route limit

These preferences are enforced on the server before an alert is sent, so this is the single place an agent decides whether their phone rings.

Parameters

This endpoint takes no parameters.

Request
curl https://magizai.com/api/agent/settings/notifications \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"
Response
{
  "settings": {
    "push_enabled": true,
    "sound_enabled": true,
    "vibrate_enabled": true,
    "email_enabled": false,
    "events": {
      "visitor_arrived":   { "push": false, "sound": null,     "label": "Visitor arrived",   "critical": false },
      "chat_started":      { "push": true,  "sound": "chime",  "label": "Chat started",      "critical": false },
      "visitor_message":   { "push": true,  "sound": "chime",  "label": "Visitor message",   "critical": false },
      "handoff_requested": { "push": true,  "sound": "urgent", "label": "Handoff requested", "critical": true  },
      "sla_breach":        { "push": true,  "sound": "urgent", "label": "SLA breach",        "critical": true  }
    },
    "sound_pack": "default",
    "volume": 70,
    "quiet_hours_start": "22:00",
    "quiet_hours_end": "07:00",
    "quiet_hours_tz": "Asia/Dubai",
    "dnd_until": null,
    "quiet_now": false,
    "dnd_now": false,
    "chatbot_filter": null,
    "only_my_conversations": false
  },
  "availability": "online",
  "push": {
    "configured": true,
    "public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U",
    "devices": 2
  },
  "chatbots": [
    { "id": 7, "name": "Support bot" }
  ]
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
PUT /api/agent/settings/notifications

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.
availability string Optional online, away or offline.
Request
curl -X PUT https://magizai.com/api/agent/settings/notifications \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "push_enabled": true,
        "volume": 70,
        "quiet_hours_start": "22:00",
        "quiet_hours_end": "07:00",
        "quiet_hours_tz": "Asia/Dubai",
        "events": {
          "visitor_arrived": { "push": false, "sound": null }
        },
        "availability": "online"
      }'
Response
{
  "settings": {
    "push_enabled": true,
    "sound_enabled": true,
    "vibrate_enabled": true,
    "email_enabled": false,
    "events": {
      "visitor_arrived":   { "push": false, "sound": null,     "label": "Visitor arrived",   "critical": false },
      "chat_started":      { "push": true,  "sound": "chime",  "label": "Chat started",      "critical": false },
      "visitor_message":   { "push": true,  "sound": "chime",  "label": "Visitor message",   "critical": false },
      "handoff_requested": { "push": true,  "sound": "urgent", "label": "Handoff requested", "critical": true  },
      "sla_breach":        { "push": true,  "sound": "urgent", "label": "SLA breach",        "critical": true  }
    },
    "sound_pack": "default",
    "volume": 70,
    "quiet_hours_start": "22:00",
    "quiet_hours_end": "07:00",
    "quiet_hours_tz": "Asia/Dubai",
    "dnd_until": null,
    "quiet_now": false,
    "dnd_now": false,
    "chatbot_filter": null,
    "only_my_conversations": false
  },
  "availability": "online"
}
Errors
Status What causes it
401 No valid token was sent.
403 The account or the workspace has been suspended.
422 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, public Rate 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.
Request
curl https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/config \
  -H "Accept: application/json"
Response
{
  "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, public Rate 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.
Request
curl -X POST https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/boot \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "visitor_id": "v_2c9a71b4e5",
        "meta": {
          "page": "https://acme.test/orders/8812",
          "visitor": { "name": "Nadia Karim", "email": "[email protected]" }
        }
      }'
Response
{
  "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, public Rate 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, public Rate 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.
Request
curl -X POST https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/chat/reset \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "visitor_id": "v_2c9a71b4e5",
        "conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91"
      }'
Response
{
  "ok": true
}
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.
GET /widget/{key}/conversations/{conversationId}/history

Polls a conversation for new messages, including replies from a human agent.

Auth None, public Rate limit 60 requests every 1 min, per IP address

Pass after with the highest message id you already hold to fetch only what is new.

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.
after integer Optional Query. Return only messages with an id greater than this.
Request
curl "https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/history?visitor_id=v_2c9a71b4e5&after=33127" \
  -H "Accept: application/json"
Response
{
  "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.
429 The route limit for this IP address was hit.
POST /widget/{key}/conversations/{conversationId}/rate

Records a thumbs up or thumbs down on one AI reply.

Auth None, public Rate limit 60 requests every 1 min, per IP address

Send rating 0 to undo a previous vote. A thumbs down is also recorded as a knowledge gap for the workspace to fix.

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.
message_id integer Required The assistant message being rated.
rating integer Required 1 for a thumbs up, -1 for a thumbs down, 0 to undo a previous vote.
Request
curl -X POST https://magizai.com/widget/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/rate \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "visitor_id": "v_2c9a71b4e5",
        "message_id": 33129,
        "rating": -1
      }'
Response
{
  "ok": true,
  "rating": -1
}
Errors
Status What causes it
404 The conversation was not found, or the message id is not an assistant message in it.
422 A field failed validation. The errors object names it.
429 The route limit for this IP address was hit.
POST /widget/{key}/conversations/{conversationId}/csat

Records a satisfaction score for the whole conversation.

Auth None, public Rate 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.