Skip to content

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 URLhttps://magiz.ai

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://magiz.ai/api/v1/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Authentication

Tokens are 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."]
  }
}
StatusWhat causes it
401The token is missing, malformed, expired or revoked.
403The token is valid but not allowed here: the wrong ability for this surface, a role without the permission, or a suspended account or workspace.
404The record does not exist, or it belongs to another workspace. The two cases are deliberately indistinguishable.
409The request conflicts with the current state, for example inviting a visitor who has already left the site.
422Validation failed, or a business rule refused the request. Read the errors object to see which field and why.
429A rate limit or an account lockout was hit. Wait the number of seconds given in the Retry-After header.
500Something failed on our side. The action did not complete.
502The AI provider could not be reached. Check the key configured for the workspace.
503A 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.

The widget on your site

One script tag installs the assistant on every page. Everything below is optional: the widget works with nothing but the key.

<script src="https://magiz.ai/widget.js" data-key="cv_9f2a4c7e1b6d3a8f5c0e2b4d" defer></script>

Attributes on the script tag

ParameterDescription
data-keyRequired. Your chatbot public key, from Chatbots then Install.
data-open="load"Opens the panel as soon as the page loads. Use it on a page whose whole purpose is the assistant, such as a chat with AI page, and leave it off everywhere else.
data-launcherForces the launcher style for this page, overriding the dashboard setting. Accepts bubble or teaser. Useful when the teaser would cover a form.
data-identityA signed identity token for the person viewing the page. See below.
data-cookie-domainScope for the cookie that keeps a conversation across subdomains, for example .example.com. Only needed when the domain has a multi part suffix such as .co.uk and the automatic guess is wrong.
data-langThe language of the chat window's own words and its direction, for visitors who read another language than the page: en, fr or ar. Without it the window follows the page's lang, then the browser's language.
data-consent="wait"Set to wait when your cookie banner decides. Until your page calls MagizAI.consent(true), the widget stores nothing in the visitor's browser (no visitor ID cookie, nothing in localStorage or sessionStorage) and sends no live visitor or browsing data. A visitor can still open the chat before that; it then works for that page only.

Calling the widget from your page

The script exposes a small object on window once it loads. Every method is safe to call before the visitor has opened the chat.

// Open the panel, optionally with the question already asked.
MagizAI.open();
MagizAI.open('Which plan suits a site with 20,000 visits a month?');

// Close it again.
MagizAI.close();

// Call this when the visitor signs out: it ends this browser's conversation
// and forgets whose it was, so the next person starts anonymously.
MagizAI.logout();

// Record a sale the chat contributed to, for the revenue report.
MagizAI.trackConversion(149.00, 'USD');

// With your cookie banner (data-consent="wait" on the script tag):
// the visitor agreed, so the widget may store its visitor ID...
MagizAI.consent(true);
// ...or said no: what the widget stored leaves this browser.
MagizAI.consent(false);
MagizAI.open() with a question is how an Ask about this plan button works: the panel opens and the question is already sent, so the visitor sees an answer rather than an empty box. Sites embedded before the rename can keep calling window.ElyAgents, which is the same object.

MagizAI.consent(true) stores the visitor ID and starts live visitors and browsing tracking, each where it is switched on and the browser does not send Do Not Track. MagizAI.consent(false) stops them for that page and removes what the widget stored in this browser: the visitor ID, the conversation link, the details the visitor gave and the widget's own preferences; an open chat goes on until the page is left. The widget does not remember the answer, so call it on every page once your banner knows it; a call made before the widget has loaded is kept. Without a banner, the chatbot setting "Store a visitor ID only after the visitor opens the chat" holds everything back the same way until the chat is opened.

Signed visitor identity

Without it the assistant treats everyone as anonymous and will not discuss an account. With it, the assistant knows who is asking and can answer about their own orders, invoices, services or tickets. Your backend signs a short compact token, HS256, using the identity secret on the chatbot; the browser only carries it.

<?php
// Server-side, in the page your signed-in customer is served. Never in the browser:
// whoever holds the secret can impersonate any of your customers.
$secret = getenv('MAGIZAI_IDENTITY_SECRET');   // Chatbots → Install → Signed visitor identity

$b64 = fn (array $a) => rtrim(strtr(base64_encode(json_encode($a)), '+/', '-_'), '=');
$header  = $b64(['alg' => 'HS256', 'typ' => 'JWT']);
$payload = $b64([
    'sub'         => (string) $user->id,      // your id for this person
    'external_id' => (string) $user->id,
    'email'       => $user->email,
    'name'        => $user->name,
    'plan'        => $user->plan,             // optional, shown to your agents
    'company'     => $user->company_name,     // optional
    'locale'      => 'en',                    // optional
    'iat'         => time(),
    'exp'         => time() + 3600,           // 24 hours is the hard ceiling
]);
$sig = rtrim(strtr(base64_encode(hash_hmac('sha256', "$header.$payload", $secret, true)), '+/', '-_'), '=');
$token = "$header.$payload.$sig";
?>
<script>window.MagizAIIdentity = "<?= $token ?>";</script>
<script src="https://magiz.ai/widget.js" data-key="cv_9f2a4c7e1b6d3a8f5c0e2b4d" defer></script>
ParameterDescription
subRequired. Your own id for this person. The conversation and its memory are bound to it. Never "0": a token that names "0" is refused.
external_idOptional alias for sub, accepted so a backend can send whichever field it already has. The same rule applies: never "0".
emailUsed to match the visitor to orders, tickets and past chats, and shown to your agents.
nameShown to your agents and used by the assistant when it greets the visitor.
planOptional. Any label you use for tier or segment. Your agents see it on the customer panel.
companyOptional. The account or organisation name.
localeOptional. Two letter language code, used when the chatbot is set to follow the signed in user rather than the browser.
iat / expIssued at and expiry, in seconds. A token is never honoured for more than 24 hours, whatever exp says. Mint a fresh one per page load.
Sign on the server and never ship the secret to the browser: anyone holding it can impersonate any of your customers. Call MagizAI.logout() when the visitor signs out, so a shared computer does not hand the next person the previous conversation.

Webhooks

The one part of the platform that calls you. Add an endpoint under Automations, on the Webhooks tab, choose the events you care about, and we POST signed JSON to your URL when they happen.

EventWhat causes it
conversation.createdA visitor opened a conversation, before anything has been said.
message.receivedA visitor sent a message.
ai.repliedThe assistant answered. Useful for logging what was said to a customer.
keyword.matchedA keyword you configured appeared in a visitor message.
handoff.requestedThe conversation asked for a human, whether the visitor asked or the assistant escalated. This is the one to wire to your alerting.
handoff.followupA visitor left contact details so your team can reply later. Sent instead of handoff.requested when the chat is already waiting for a person, or when the last handoff got no answer. Wire it to your alerting too.
conversation.resolvedA conversation was closed, by an agent or by the assistant. The usual trigger for closing your own ticket.
tag.addedA tag was applied to a conversation.
lead.capturedContact details were captured. The usual trigger for creating a CRM record.
lead.requestA visitor confirmed a request for your team in the chat, such as a callback or a quote. The contact and what they asked for arrive under data.lead.
conversion.recordedRevenue was attributed to a conversation.
action.executedThe assistant ran one of your actions, such as a skill or a connected tool.
booking.createdA booking was made and needs no approval. The booking arrives under data.booking, with no link that could change it.
booking.requestedA booking request came in and waits for your team to confirm or decline it.
booking.confirmedA booking request was confirmed.
booking.declinedA booking request was declined.
booking.cancelledA booking was cancelled, by the customer or by your team.
booking.rescheduledA booking was moved to another time.
booking.completedA booking was marked done.
booking.no_showA customer did not come to their booking.

Every delivery has the same envelope: the event name, when it happened, and a data object. Eloquent records are never serialised raw, so data carries plain fields only, and a conversation always arrives under data.conversation with its public_id.

POST https://your-app.example.com/hooks/magizai
Content-Type: application/json
User-Agent: MagizAI-Webhooks/1.0
X-Signature: sha256=6f1b0c2e…

{
  "event": "conversation.resolved",
  "timestamp": "2026-09-23T09:14:02+00:00",
  "data": {
    "conversation": {
      "public_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
      "status": "closed",
      "channel": "website",
      "visitor_name": "Nadia Karim",
      "visitor_email": "nadia@example.test",
      "visitor_page": "https://example.com/pricing"
    }
  }
}

Verifying a delivery

Each request carries X-Signature: sha256= followed by an HMAC of the exact bytes we sent, keyed with your endpoint secret. Check it before you trust the body, and compare in constant time.

// Node / Express. Verify against the RAW body, before any JSON parsing:
// re-serialising changes the bytes and the signature will never match.
app.post('/hooks/magizai', express.raw({ type: 'application/json' }), (req, res) => {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.MAGIZAI_WEBHOOK_SECRET)
    .update(req.body)
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(req.get('X-Signature') || '');
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return res.sendStatus(401);

  const { event, data } = JSON.parse(req.body.toString('utf8'));
  // Answer first, work afterwards: anything slower than 10 seconds counts as a failure.
  res.sendStatus(200);
  queue.push({ event, data });
});
RuleDescription
Public HTTPS onlyThe URL must resolve to a public address. Internal and loopback addresses are refused, the connection is pinned to the verified address, and redirects are not followed.
10 second timeoutAnswer with a 2xx as soon as you have the payload and do the work afterwards. Anything slower counts as a failed delivery.
3 attemptsA failure or an answer outside 2xx is tried again up to twice, a few seconds to a minute apart, so three attempts in all. After the third the delivery stays marked failed in the log. An address the public address check refuses is not tried again.
No ordering guaranteeDeliveries are queued, so two events can arrive out of order and a retry can arrive twice. Treat the payload as a fact to apply rather than a step to replay, and key on public_id.
Every delivery is loggedStatus, response code and the first 2000 characters of your response are kept, and Send test posts a sample payload. Read that log first when something does not arrive.

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/v19 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://magiz.ai/api/v1/me \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Response

{
  "user": {
    "id": 12,
    "name": "Amelia Fox",
    "email": "amelia@acme.test",
    "role": "owner"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "slug": "acme-ltd",
    "plan": "pro"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.

Request

curl https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
per_pageintegerOptionalQuery. Rows per page. Defaults to 20 and is capped at 100.

Request

curl "https://magiz.ai/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://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=1",
  "from": 1,
  "last_page": 34,
  "last_page_url": "https://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=34",
  "next_page_url": "https://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations?page=2",
  "path": "https://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/conversations",
  "per_page": 2,
  "prev_page_url": null,
  "to": 2,
  "total": 67
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.

GET/api/v1/chatbots/{key}/knowledge

Lists the documents a chatbot holds, newest first, as a paginated result.

Auth Bearer token (api)Rate limit No route limit

The pages a crawled URL expanded into are left out, so the count matches what an admin sees on the Knowledge screen. Filter by source_url_prefix to ask only about the documents your own integration pushed, which is how a sync reconciles what it sent with what is actually there.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
typestringOptionalReturn only this kind: text, qa, url or file.
source_url_prefixstringOptionalReturn only documents whose address starts with this.
per_pageintegerOptionalQuery. Rows per page. Defaults to 20 and is capped at 100.

Request

curl "https://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge?source_url_prefix=https://example.com/help/&per_page=50" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Response

{
  "data": [
    {
      "id": 918,
      "type": "text",
      "title": "Refund policy",
      "source_url": "https://example.com/help/refund-policy",
      "status": "ready",
      "chunk_count": 3,
      "created_at": "2026-09-14T08:21:55+00:00"
    }
  ],
  "current_page": 1,
  "per_page": 50,
  "total": 1,
  "last_page": 1
}

Errors

StatusWhat causes it
401No valid token was sent.
404No such record in this workspace.
422A field failed validation. The errors object names it.

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-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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
titlestringRequiredA name for the document. Up to 200 characters.
contentstringRequiredThe document text.
typestringOptionaltext or qa. Defaults to text.
source_urlstringOptionalRequired when type is url. The page to crawl, up to 2048 characters.
visibilitystringOptionalpublic or customer. A customer document is only used when the visitor is identified by a signed token.

Request

curl -X POST https://magiz.ai/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",
        "source_url": "https://example.com/help/refund-policy",
        "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,
    "source_url": "https://example.com/help/refund-policy"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A field failed validation. The errors object names it.
422The document was saved but could not be trained. The response carries its id and status so you can retry training instead of uploading again.

DELETE/api/v1/chatbots/{key}/knowledge

Removes pushed documents: the one at source_url, or everything under url_prefix except the addresses you list in keep.

Auth Bearer token (api)Role ability manage-contentRate limit No route limit

This is how a sync removes articles that were deleted at the source: send the URLs you still have as keep, and anything else you once pushed under that prefix goes. It never touches crawled pages, uploads, or documents added by hand in the dashboard.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
source_urlstringOptionalRemove the single document pushed with this address. Required unless url_prefix is given.
url_prefixstringOptionalRemove every pushed document whose address starts with this. Must include a path, not just a domain.
keeparrayOptionalAddresses to spare when using url_prefix. Up to 5000.

Request

curl -X DELETE https://magiz.ai/api/v1/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "url_prefix": "https://example.com/help/",
        "keep": [
          "https://example.com/help/refund-policy",
          "https://example.com/help/delivery-times"
        ]
      }'

Response

{
  "data": {
    "removed": 14
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A field failed validation. The errors object names it.
422url_prefix has no path. A bare domain would sweep every document the chatbot holds, so it is refused.

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-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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
messagestringRequiredThe visitor message. Up to 4000 characters, and it cannot be only whitespace.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_iduuidOptionalAn existing conversation to continue. Leave it out to start a new one.
metaobjectOptionalFree-form context stored on the conversation.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A field failed validation. The errors object names it.
429The workspace has reached its monthly message limit.
502The 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.

AI API

MagizAI's AI for your own software, with no chatbot: write, rewrite, summarise, extract, classify, translate, and answer questions from your business's trained knowledge. It can also start a run of one of the workspace's AI agents and read how it went. A workspace manager switches on the AI API app, then makes a token with "Can use the AI API" ticked in Settings, API tokens. Each call counts as one AI message on the plan, like a chat reply, and as one of the plan's AI API calls this month. Every error carries a stable code: app_off, no_ability, invalid, health_off, cap, rate_limited, no_ai, failed, not_found, agents_off, agents_stopped or agent_unavailable. Do not send health records unless the workspace has switched on AI for health data, and then mark the call with contains_health_data.

Base path/api/v1/ai5 endpoints

POST/api/v1/ai/complete

Runs one AI task on the text you send. Returns text, or fields for extract and classify.

Auth Bearer token (api)Role ability aiRate limit 60 requests every 1 min, per token

The result is a suggestion: check it before it reaches a customer or changes a record. For extract, a field the text does not give is null. For classify, each field holds one of its options, or null.

Parameters

ParameterTypeRequiredDescription
purposestringRequiredOne of write, rewrite, summarise, extract, classify, translate, answer.
inputstringRequiredThe text to work on: the brief for write, the text with its question for answer. Up to 10000 characters.
languagestringOptionalWrite in this language, as a code such as fr or a name such as French. Required for translate. Default: the language of the text.
tonestringOptionalOne of neutral, friendly, formal, warm.
fieldsarrayOptionalFor extract and classify: up to 25 field names, or objects with name, description and options. Classify needs options for every field.
contains_health_databooleanOptionaltrue when the text carries health data. Refused unless the workspace switched on AI for health data.

Request

curl -X POST https://magiz.ai/api/v1/ai/complete \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "purpose": "extract",
        "input": "Hi, this is Sara Bell. My order A-1055 has not arrived in Dubai yet.",
        "fields": ["name", "order_number", "city"]
      }'

Response

{
  "purpose": "extract",
  "fields": {
    "name": "Sara Bell",
    "order_number": "A-1055",
    "city": "Dubai"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403app_off: the AI API app is off for the workspace.
403no_ability: the token was made without the ai ability, or its owner can no longer manage the workspace.
403health_off: the call is marked contains_health_data and AI for health data is off.
422invalid: a field failed validation. The errors object names it.
429cap: this month's AI API calls, or the plan's AI messages, are used up.
429rate_limited: too many calls with this token in a minute. Retry-After says when to try again.
502failed: the AI did not give a usable answer. Try again.
503no_ai: the workspace has no AI that can answer now (no working AI key, or the workspace is not active).

POST/api/v1/ai/answer

Answers a question from the workspace's trained knowledge and lists the sources it used.

Auth Bearer token (api)Role ability aiRate limit 30 requests every 1 min, per token

Reads only public passages unless audience is staff. knowledge says what the search found: used, none_found, no_knowledge or unavailable. When nothing matches, the model is told to say so rather than guess.

Parameters

ParameterTypeRequiredDescription
questionstringRequiredThe question. Up to 2000 characters.
languagestringOptionalWrite in this language, as a code such as fr or a name such as French. Required for translate. Default: the language of the text.
audiencestringOptionalpublic (the default) reads only public passages. staff also reads passages for signed-in customers and internal notes.
contains_health_databooleanOptionaltrue when the text carries health data. Refused unless the workspace switched on AI for health data.

Request

curl -X POST https://magiz.ai/api/v1/ai/answer \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "question": "Do you deliver to Dubai, and how long does it take?"
      }'

Response

{
  "answer": "Yes. Orders to Dubai arrive in two to four working days with DHL Express.",
  "knowledge": "used",
  "sources": [
    {
      "title": "Shipping and delivery",
      "url": "https://acme.test/shipping"
    }
  ]
}

Errors

StatusWhat causes it
401No valid token was sent.
403app_off: the AI API app is off for the workspace.
403no_ability: the token was made without the ai ability, or its owner can no longer manage the workspace.
403health_off: the call is marked contains_health_data and AI for health data is off.
422invalid: a field failed validation. The errors object names it.
429cap: this month's AI API calls, or the plan's AI messages, are used up.
429rate_limited: too many calls with this token in a minute. Retry-After says when to try again.
502failed: the AI did not give a usable answer. Try again.
503no_ai: the workspace has no AI that can answer now (no working AI key, or the workspace is not active).

GET/api/v1/ai/agents

Lists the workspace's active agents that a token may run.

Auth Bearer token (api)Role ability aiRate limit 60 requests every 1 min, per token

An agent that works with health details is not listed: it never runs through the API. can_act is true when the agent may ask for actions, which wait for a manager in the dashboard. Needs the Agents app switched on.

Parameters

This endpoint takes no parameters.

Request

curl https://magiz.ai/api/v1/ai/agents \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Response

{
  "data": [
    {
      "id": 12,
      "name": "Billing desk",
      "version": 3,
      "tools": [
        "customer_lookup",
        "customer_balance",
        "message_draft"
      ],
      "can_act": false
    },
    {
      "id": 14,
      "name": "Customer care",
      "version": 1,
      "tools": [
        "customer_lookup",
        "customer_tag",
        "customer_note"
      ],
      "can_act": true
    }
  ]
}

Errors

StatusWhat causes it
401No valid token was sent.
403app_off: the AI API app is off for the workspace.
403agents_off: the Agents app is off for the workspace.
403no_ability: the token was made without the ai ability, or its owner can no longer manage the workspace.
429rate_limited: too many calls with this token in a minute. Retry-After says when to try again.

POST/api/v1/ai/agents/{id}/runs

Starts a run of one agent with a task. Answers at once with the run, or when it ends within wait seconds.

Auth Bearer token (api)Role ability aiRate limit 10 requests every 1 min, per token

The run keeps every rule of the Agents app: the agent's own limits, the cost caps and the stop switch. Each model call counts as one AI API call and one AI message. Status 202 means the run is still going: read it with GET /api/v1/ai/runs/{id}. Actions and drafts wait for a manager on the run's page in the dashboard (dashboard_url); the API cannot approve them. Needs the Agents app switched on.

Parameters

ParameterTypeRequiredDescription
idintegerRequiredPath. The agent's id, from GET /api/v1/ai/agents.
taskstringRequiredWhat the agent is asked to do. Up to 4000 characters.
inputsobjectOptionalUp to 20 named values, such as {"invoice": "INV-0107"}. Names use letters, digits and _. The agent reads them as data, never as instructions.
waitintegerOptionalSeconds to hold the call for the run to end, 0 to 25. Default 0: an answer at once with status 202.

Request

curl -X POST https://magiz.ai/api/v1/ai/agents/12/runs \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
        "task": "Check what Ananya Rao owes and draft a polite reminder.",
        "inputs": {"customer": "Ananya Rao"},
        "wait": 20
      }'

Response

{
  "run": {
    "id": 845,
    "agent": {
      "id": 12,
      "name": "Billing desk",
      "version": 3
    },
    "status": "done",
    "ended": "done",
    "output": "Ananya Rao owes INR 4,500 on invoice INV-0107, due on 20 October. I saved a reminder email as a draft for you to check.",
    "approval": "pending",
    "actions": [],
    "drafts": 1,
    "dashboard_url": "https://magiz.ai/agents/runs/845",
    "usage": {
      "model_calls": 3,
      "tool_calls": 2,
      "tokens_in": 4120,
      "tokens_out": 310,
      "cost_usd": "0.004380"
    },
    "started_at": "2026-10-16T09:12:03.120Z",
    "finished_at": "2026-10-16T09:12:09.874Z"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403app_off: the AI API app is off for the workspace.
403agents_off: the Agents app is off for the workspace.
403no_ability: the token was made without the ai ability, or its owner can no longer manage the workspace.
404not_found: no such agent in the workspace.
409agent_unavailable: the agent is archived, or works with health details.
409agents_stopped: a workspace manager stopped every agent.
422invalid: a field failed validation. The errors object names it.
429cap: this month's AI API calls or the plan's AI messages are used up, or the agents' cost cap for today is reached.
429rate_limited: too many calls with this token in a minute. Retry-After says when to try again.

GET/api/v1/ai/runs/{id}

Reads a run started through the AI API: its state, its answer, what waits for a manager and what it used.

Auth Bearer token (api)Role ability aiRate limit 120 requests every 1 min, per token

status is running, waiting, done, stopped or failed. ended says how it ended, such as done, waiting, step_limit, time_limit, cap or rejected. approval is pending while a manager has to decide. Runs started from the dashboard, a workflow or a chat cannot be read here.

Parameters

ParameterTypeRequiredDescription
idintegerRequiredPath. The run's id, from the call that started it.

Request

curl https://magiz.ai/api/v1/ai/runs/846 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Response

{
  "run": {
    "id": 846,
    "agent": {
      "id": 14,
      "name": "Customer care",
      "version": 1
    },
    "status": "waiting",
    "ended": "waiting",
    "output": "I asked to tag Ananya Rao as a late payer.",
    "approval": "pending",
    "actions": [
      {
        "id": 77,
        "tool": "customer_tag",
        "status": "pending"
      }
    ],
    "drafts": 0,
    "dashboard_url": "https://magiz.ai/agents/runs/846",
    "usage": {
      "model_calls": 2,
      "tool_calls": 2,
      "tokens_in": 2890,
      "tokens_out": 120,
      "cost_usd": "0.002710"
    },
    "started_at": "2026-10-16T09:20:41.502Z",
    "finished_at": "2026-10-16T09:20:45.019Z"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403app_off: the AI API app is off for the workspace.
403agents_off: the Agents app is off for the workspace.
403no_ability: the token was made without the ai ability, or its owner can no longer manage the workspace.
404not_found: no such run in the workspace started through the AI API.
429rate_limited: too many calls with this token in a minute. Retry-After says when to try again.

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/portal20 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

ParameterTypeRequiredDescription
emailstringRequiredThe email address of a dashboard user. Up to 255 characters.
passwordstringRequiredThat user dashboard password.

Request

curl -X POST https://magiz.ai/api/portal/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "email": "amelia@acme.test",
        "password": "correct-horse-battery-staple"
      }'

Response

{
  "token": "17|Ck2Ft9pQvYb3xLmR8sJd0aWnZeH6uT4gPqK1oI5c",
  "user": {
    "name": "Amelia Fox",
    "email": "amelia@acme.test",
    "role": "owner"
  },
  "company": {
    "name": "Acme Ltd",
    "plan": "pro"
  },
  "brand": {
    "name": "Acme Support",
    "powered_by": "MagizAI",
    "logo_url": "https://cdn.acme.test/logo.svg"
  }
}

Errors

StatusWhat causes it
401The email or password was wrong. The wording is the same whether or not the address exists.
403The 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.
422A field failed validation. The errors object names it.
429Too 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://magiz.ai/api/portal/logout \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "message": "Signed out."
}

Errors

StatusWhat causes it
401No valid token was sent.
403The 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://magiz.ai/api/portal/me \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "user": {
    "name": "Amelia Fox",
    "email": "amelia@acme.test",
    "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

StatusWhat causes it
401No valid token was sent.
403The 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.

Request

curl https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.

GET/api/portal/chatbots/{key}/options

Returns every value the update endpoint will accept: AI providers and models this plan allows, quality tiers, themes, layouts, launchers, reply styles and composer styles.

Auth Bearer token (portal)Rate limit No route limit

Read this before building an edit form rather than hard coding the lists. The choices depend on the plan and on whether the workspace is using its own provider key, and they change as plans change. Provider keys themselves are never returned, only whether one is on file.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.

Request

curl https://magiz.ai/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/options \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "data": {
    "key_mode": "platform",
    "providers": [
      {
        "key": "openai",
        "label": "OpenAI",
        "models": ["gpt-4o-mini", "gpt-4o"],
        "has_key": false
      }
    ],
    "tiers": [
      { "key": "fastest",  "label": "Fastest",  "help": "Quickest replies at the lowest cost." },
      { "key": "standard", "label": "Standard", "help": "The balanced default." },
      { "key": "advanced", "label": "Advanced", "help": "Deepest reasoning for hard questions." }
    ],
    "themes": ["minimal", "ocean", "emerald", "midnight", "sunset", "crisp", "violet", "rose", "slate", "forest"],
    "layouts": ["classic", "hub", "compact"],
    "launchers": ["bubble", "teaser"],
    "reply_styles": ["bubbles", "flat", "cards", "compact", "spacious", "speech", "outline", "document", "terminal", "pill", "square", "notes"],
    "composer_styles": ["full", "minimal"],
    "current": {
      "provider": "openai",
      "model": "gpt-4o-mini",
      "ai_tier": "standard"
    }
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.

PUT/api/portal/chatbots/{key}

Updates a chatbot content and widget appearance.

Auth Bearer token (portal)Role ability manage-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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
namestringRequiredThe chatbot name. Up to 120 characters.
personastringOptionalHow the assistant should sound. Up to 2000 characters.
instructionsstringOptionalStanding instructions for the assistant. Up to 4000 characters.
welcome_messagestringOptionalThe greeting shown when the chat opens. Up to 300 characters; empty resets it to the default.
is_activebooleanOptionalWhether the chatbot answers. Leave it out to keep the current setting.
primary_colorstringOptionalWidget accent colour as a hex value. Up to 9 characters.
launcher_textstringOptionalLabel on the chat launcher. Up to 40 characters.
positionstringOptionalWhich side the widget sits on: left or right.
themestringOptionalWidget theme: minimal, ocean, emerald, midnight, sunset, crisp, violet, rose, slate or forest.

Request

curl -X PUT https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.

Request

curl https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No 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-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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
typestringRequiredtext, qa or url. It decides which of the fields below are required.
titlestringOptionalA name for the source. Left out, it falls back to a sensible default for the type.
contentstringOptionalRequired when type is text. The note body, up to 1,000,000 characters.
questionstringOptionalRequired when type is qa. Up to 2000 characters.
answerstringOptionalRequired when type is qa. Up to 50,000 characters.
source_urlurlOptionalRequired when type is url. The page to crawl, up to 2048 characters.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A 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-contentRate limit No route limit

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
sourceintegerRequiredPath. The knowledge source id.

Request

curl -X DELETE https://magiz.ai/api/portal/chatbots/cv_9f2a4c7e1b6d3a8f5c0e2b4d/knowledge/919 \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "message": "Knowledge source removed."
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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-workspaceRate limit No route limit

Parameters

ParameterTypeRequiredDescription
providerstringRequiredPath. Provider slug: claude, openai, gemini, deepseek, kimi, groq, mistral or openrouter.
api_keystringRequiredThe provider API key. Stored encrypted and never returned. Up to 300 characters.

Request

curl -X PUT https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
422That provider slug is not recognised.
422A 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-workspaceRate limit No route limit

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

Parameters

ParameterTypeRequiredDescription
providerstringRequiredPath. Provider slug: claude, openai, gemini, deepseek, kimi, groq, mistral or openrouter.

Request

curl -X DELETE https://magiz.ai/api/portal/keys/openai \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "message": "API key removed."
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
422That provider slug is not recognised.

GET/api/portal/conversations

The conversation list, with unread counts and section totals.

Auth Bearer token (portal)Role ability view-inboxRate limit No route limit

The same feed the dashboard inbox and the agent apps read, so the two can never drift apart. Pass filter to narrow it: all, waiting, mine, team, ai or resolved. Up to 60 rows come back, most urgent first.

Parameters

ParameterTypeRequiredDescription
filterstringOptionalQuery. Narrow the list: all, waiting, mine, team, ai, human or resolved. Defaults to all.
conversationuuidOptionalQuery. Open this conversation, return it in active and mark it read.

Request

curl "https://magiz.ai/api/portal/conversations?filter=waiting" \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "conversations": [
    {
      "id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
      "chatbot": "Support bot",
      "visitor": "Nadia Karim",
      "email": "nadia@example.test",
      "status": "agent",
      "channel": "website",
      "last_at": "2 minutes ago",
      "preview": "I still have not received the replacement…",
      "escalated": true,
      "unread": 2,
      "tags": [],
      "group": "waiting",
      "handoff_state": "handoff_pending",
      "assigned_to": null,
      "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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
403The account or the workspace has been suspended.

GET/api/portal/conversations/{conversation}

One conversation with its full transcript, and marks it read.

Auth Bearer token (portal)Role ability view-inboxRate limit No route limit

Reading needs view-inbox only, so a client can give a colleague visibility of their chats without the ability to answer customers.

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl https://magiz.ai/api/portal/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91 \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "active": {
    "id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
    "visitor": "Nadia Karim",
    "email": "nadia@example.test",
    "status": "agent",
    "channel": "website",
    "handoff_state": "human_connected",
    "messages": [
      { "id": 33128, "role": "visitor", "content": "Where is my replacement?", "at": "10:14 AM" },
      { "id": 33129, "role": "assistant", "content": "Let me check that order for you.", "at": "10:14 AM" },
      { "id": 33131, "role": "agent", "content": "It ships tomorrow, tracking to follow.", "at": "10:16 AM", "agent": "Sara" }
    ]
  },
  "conversations": [],
  "counts": { "all": 412, "ai": 301, "human": 74, "resolved": 37, "unread": 5 }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.

POST/api/portal/conversations/{conversation}/reply

Replies to a visitor as a human, and takes the conversation over from the AI.

Auth Bearer token (portal)Role ability handle-conversationsRate limit 60 requests every 1 min, per signed-in user

Sending a reply stops the AI answering that conversation and cancels any pending handoff timer. Pass client_id on a retry: if the first attempt did reach us, the stored message is returned instead of the customer receiving it twice.

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
bodystringRequiredThe reply to send. Up to 4000 characters, and it cannot be only whitespace.
client_idstringOptionalYour 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://magiz.ai/api/portal/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/reply \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "body": "It ships tomorrow, tracking to follow.",
        "client_id": "outbox-8821"
      }'

Response

{
  "message": {
    "id": 33131,
    "role": "agent",
    "content": "It ships tomorrow, tracking to follow.",
    "at": "10:16 AM"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422The reply was only whitespace.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.

POST/api/portal/conversations/{conversation}/resolve

Closes a conversation and fires the conversation.resolved webhook.

Auth Bearer token (portal)Role ability handle-conversationsRate limit No route limit

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/portal/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/resolve \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "closed",
  "resolution": "resolved"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.

POST/api/portal/conversations/{conversation}/reopen

Reopens a closed conversation and hands it back to the AI.

Auth Bearer token (portal)Role ability handle-conversationsRate limit No route limit

The visitor keeps their history: reopening continues the same thread rather than starting a new one.

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/portal/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/reopen \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "bot"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.

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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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://magiz.ai/api/portal/widget-snippet \
  -H "Authorization: Bearer $PORTAL_TOKEN" \
  -H "Accept: application/json"

Response

{
  "data": {
    "public_key": "cv_9f2a4c7e1b6d3a8f5c0e2b4d",
    "snippet": "<script src=\"https://magiz.ai/widget.js\" data-key=\"cv_9f2a4c7e1b6d3a8f5c0e2b4d\" defer></script>"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404The 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. Where the workspace has Queue, Bookings or Customers switched on, it also runs the front desk: the day's queue, the day's agenda and the people register. Every action runs the same tenant logic as the dashboard, so behaviour matches exactly.

Base path/api/agent44 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. With two-step login on, the code is sent with the email and password; a workspace that requires two-step login gives no token to a person who has not turned it on.

Parameters

ParameterTypeRequiredDescription
emailstringRequiredThe email address of a dashboard user. Up to 255 characters.
passwordstringRequiredThat user dashboard password.
device_namestringOptionalA label for this device, shown beside the token. Up to 120 characters.
codestringOptionalOnly when two-step login is on for this account: the 6-digit code from the authenticator app, or a recovery code, sent with the same email and password.

Request

curl -X POST https://magiz.ai/api/agent/login \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
        "email": "sara@acme.test",
        "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": "sara@acme.test",
    "role": "Agent",
    "avatar": "https://cdn.acme.test/avatars/58.png"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "plan": "pro"
  }
}

Errors

StatusWhat causes it
401The email or password was wrong. The wording is the same whether or not the address exists.
401Two-step login is on for this account: two_factor is code_required when no code was sent, wrong_code when it did not match. Code tries are limited to 6 per 5 minutes per account and address.
403This account cannot handle conversations, or its workspace is unavailable.
403The two_factor field says setup_required: the workspace requires two-step login of this person and it is not on. They turn it on in their profile on the web, then sign in again.
422A field failed validation. The errors object names it.
429Too 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://magiz.ai/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": "sara@acme.test",
    "role": "Agent",
    "avatar": "https://cdn.acme.test/avatars/58.png"
  },
  "company": {
    "id": 3,
    "name": "Acme Ltd",
    "plan": "pro"
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403The two_factor field says setup_required: the workspace now requires two-step login of this person and it is not on. The token is deleted; sign in again once it is on.
429The 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://magiz.ai/api/agent/me \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "user": {
    "id": 58,
    "name": "Sara Bell",
    "email": "sara@acme.test",
    "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

StatusWhat causes it
401No valid token was sent.
403The 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://magiz.ai/api/agent/logout \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "message": "Signed out."
}

Errors

StatusWhat causes it
401No valid token was sent.
403The 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

ParameterTypeRequiredDescription
socket_idstringRequiredThe socket id given by the realtime connection.
channel_namestringRequiredThe channel being subscribed to.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403The 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)Role ability view-inboxRate 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

ParameterTypeRequiredDescription
filterstringOptionalQuery. Narrow the list: all, waiting, mine, team, ai, human or resolved. Defaults to all.
conversationuuidOptionalQuery. Open this conversation, return it in active and mark it read.

Request

curl "https://magiz.ai/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": "nadia@example.test",
      "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

StatusWhat causes it
401No valid token was sent.
403The 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)Role ability view-inboxRate 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl https://magiz.ai/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": "nadia@example.test",
    "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": "nadia@example.test" }
    ],
    "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

StatusWhat causes it
401No valid token was sent.
403The 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-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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
bodystringRequiredThe reply to send. Up to 4000 characters, and it cannot be only whitespace.
client_idstringOptionalYour 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422The reply was only whitespace.
422A field failed validation. The errors object names it.

GET/api/agent/attachments/options

What this agent may attach: accepted types, the size cap and how many files per send.

Auth Bearer token (agent)Role ability view-inboxRate limit No route limit

Read it at launch rather than hard coding the limits, so a change on the platform reaches an installed app without a store release.

Parameters

This endpoint takes no parameters.

Request

curl https://magiz.ai/api/agent/attachments/options \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "accept": "image/jpeg,.jpg,image/png,.png,image/gif,.gif,image/webp,.webp,application/pdf,.pdf,text/plain,.txt,text/csv,.csv,…",
  "max_bytes": 2097152,
  "max_label": "2 MB",
  "max_files": 5,
  "types_label": "JPG, PNG, GIF, WEBP, PDF, TXT, CSV, DOCX, XLSX or PPTX"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.

POST/api/agent/conversations/{conversation}/attachments

Sends one to five files to the visitor, with an optional caption.

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

Sending a file is replying: it takes the conversation over exactly as a text reply does, and the file is delivered on whichever channel the visitor is on. A partial batch returns 207 with the messages that were sent and the files that were refused, because discarding work that already succeeded is worse than a mixed result.

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
files[]fileRequiredOne to five files, sent as multipart form data. Anything outside the accepted types, or over the size cap, is refused per file.
captionstringOptionalText sent with the first file. The rest carry their filename.
client_idstringOptionalYour 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://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/attachments \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json" \
  -F "files[]=@/path/to/replacement-label.pdf" \
  -F "caption=Here is the return label." \
  -F "client_id=outbox-2026-08-08-0008"

Response

{
  "messages": [
    {
      "id": 33140,
      "role": "agent",
      "content": "Here is the return label.",
      "at": "10:52 AM",
      "attachment": {
        "id": "at_5b1c9d3e7a2f",
        "url": "https://example.com/inbox/attachments/at_5b1c9d3e7a2f",
        "thumb_url": null,
        "is_image": false,
        "name": "replacement-label.pdf",
        "mime": "application/pdf",
        "kind": "document",
        "size": 84213,
        "size_label": "82 KB"
      }
    }
  ],
  "errors": []
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
207Some files were sent and some were refused. The response carries both lists.
422No file could be sent. Every file in the batch was refused, and errors says why for each one.
429The route limit for this user was hit.

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-conversationsRate limit No route limit

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/takeover \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "agent"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No 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-conversationsRate limit No route limit

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/release \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "bot"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.

POST/api/agent/conversations/{conversation}/resolve

Closes the conversation as resolved.

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

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

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/resolve \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "closed",
  "resolution": "resolved"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No 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-conversationsRate limit No route limit

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/reopen \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "status": "bot"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.

GET/api/agent/tags

Lists the workspace tag catalogue.

Auth Bearer token (agent)Role ability view-inboxRate limit No route limit

Parameters

This endpoint takes no parameters.

Request

curl https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.

POST/api/agent/conversations/{conversation}/tags

Attaches a catalogue tag to a conversation.

Auth Bearer token (agent)Role ability view-inboxRate limit No route limit

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

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
tag_idintegerRequiredThe id of a tag already in the workspace catalogue.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.
422A 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)Role ability view-inboxRate limit No route limit

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
tagintegerRequiredPath. The tag id.

Request

curl -X DELETE https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/tags/4 \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "detached": 4
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No such record in this workspace.

GET/api/agent/canned

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

Auth Bearer token (agent)Role ability view-inboxRate 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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-conversationsRate limit No route limit

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

Parameters

ParameterTypeRequiredDescription
cannedintegerRequiredPath. The canned reply id.

Request

curl -X POST https://magiz.ai/api/agent/canned/19/used \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "ok": true
}

Errors

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
403The canned reply belongs to another agent and is not shared.
404No 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)Role ability view-inboxRate 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl https://magiz.ai/api/agent/conversations/6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91/customer-context \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "email": "nadia@example.test",
  "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": "nadia@example.test"
      },
      "subscriptions": [
        {
          "status": "active",
          "plan": "Care Plus",
          "amount": "29.00 AED",
          "renews": "Sep 1, 2026"
        }
      ]
    }
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404No 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-conversationsRate 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
amountnumberOptionalDeal value in whole currency units, up to 100,000,000. Send null to clear it.
currencystringOptionalThree-letter currency code. Falls back to the value already on the conversation, then to USD.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A 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-conversationsRate 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422No 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-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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
draftstringOptionalWhat the agent has typed so far, so the suggestion builds on it. Up to 4000 characters.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422A field failed validation. The errors object names it.
429The 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-conversationsRate 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

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.
bodystringRequiredThe draft to rewrite. Up to 4000 characters, and it cannot be only whitespace.
modestringOptionalfix, professional, friendly, concise or expand. Defaults to fix.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422The draft was only whitespace.
422A field failed validation. The errors object names it.
429The 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-conversationsRate limit 30 requests every 1 min, per signed-in user

Parameters

ParameterTypeRequiredDescription
conversationuuidRequiredPath. The conversation public id, a UUID.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No such record in this workspace.
422No summary could be generated right now.
429The 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-conversationsRate limit 60 requests every 1 min, per signed-in user

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

Parameters

ParameterTypeRequiredDescription
suggestionintegerRequiredPath. The id returned by the suggest endpoint.
outcomestringRequiredgenerated, inserted, edited or dismissed.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The token is valid, but the user role does not grant this action.
404No suggestion with that id in this workspace.
422A field failed validation. The errors object names it.
429The 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)Role ability view-inboxRate 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

ParameterTypeRequiredDescription
limitintegerOptionalQuery. How many visitors to return. Clamped between 1 and 200; defaults to 100.

Request

curl "https://magiz.ai/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": "nadia@example.test",
      "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

StatusWhat causes it
401No valid token was sent.
403The 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)Role ability view-inboxRate 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

ParameterTypeRequiredDescription
visitorstringRequiredPath. The visitor id from the live visitors list. Trimmed to 100 characters.
messagestringRequiredThe opening line to send. Up to 2000 characters, and it cannot be only whitespace.
chatbot_idintegerOptionalSend from this chatbot. Left out, the visitor own chatbot is preferred, then any active one.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
404The visitor id was empty after trimming.
409That visitor is no longer on the site.
422The workspace has no active chatbot to send from.
429The route limit for this user was hit.
500The 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://magiz.ai/api/agent/push/vapid \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "configured": true,
  "public_key": "BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The 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

ParameterTypeRequiredDescription
endpointurlRequiredThe push endpoint issued by the browser. Must be an https URL, up to 2048 characters.
keysobjectRequiredThe subscription key pair from the browser.
keys.p256dhstringRequiredThe p256dh key from the browser subscription. Up to 255 characters.
keys.authstringRequiredThe auth secret from the browser subscription. Up to 255 characters.
device_namestringOptionalA label for this device, shown beside the token. Up to 120 characters.
platformstringOptionalios, android or desktop.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
422The endpoint is not an https URL, so it cannot be a real push service.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.
500The 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

ParameterTypeRequiredDescription
endpointstringRequiredThe push endpoint to remove. Up to 2048 characters.

Request

curl -X DELETE https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
422A 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://magiz.ai/api/agent/push/test \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "ok": true,
  "result": {
    "sent": 2,
    "failed": 0,
    "pruned": 0
  }
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
422No device received the test. Allow notifications on the device and try again.
429The route limit for this user was hit.
503Push 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://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The 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

ParameterTypeRequiredDescription
push_enabledbooleanOptionalMaster switch for push alerts on this account.
sound_enabledbooleanOptionalWhether alerts play a sound.
vibrate_enabledbooleanOptionalWhether alerts vibrate the device.
email_enabledbooleanOptionalWhether alerts are also sent by email.
eventsobjectOptionalPer-event settings, keyed by event: visitor_arrived, chat_started, visitor_message, handoff_requested, sla_breach. Merged with what is stored.
events.*.pushbooleanOptionalWhether this event sends a push. Required for each event you include.
events.*.soundstringOptionalSound name for this event, or null for the default. Up to 24 characters.
sound_packstringOptionalName of the sound pack. Up to 24 characters.
volumeintegerOptionalAlert volume from 0 to 100.
quiet_hours_startstringOptionalStart of quiet hours as HH:MM, read in the agent own timezone.
quiet_hours_endstringOptionalEnd of quiet hours as HH:MM. It must be sent together with the start.
quiet_hours_tzstringOptionalTimezone the quiet hours are read in, for example Asia/Dubai. Up to 64 characters.
dnd_minutesintegerOptionalSilence alerts for this many minutes, from 0 to 1440. Send 0 to clear.
chatbot_filterarrayOptionalOnly alert on these chatbot ids. Ids outside the workspace are dropped, and an empty result clears the filter.
only_my_conversationsbooleanOptionalOnly alert on conversations assigned to this agent.
availabilitystringOptionalonline, away or offline.

Request

curl -X PUT https://magiz.ai/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

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
422Quiet hours need both a start and an end time; half a window would do nothing.
422A field failed validation. The errors object names it.
500The settings could not be saved.

GET/api/agent/apps

Lists the app tabs this person may open in the agent apps: Queue, Bookings and Customers, each only while it is switched on for the workspace. Health apps are never listed.

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

An app is listed when it is on in Apps and the person holds the ability its dashboard screens need. Ask again whenever the app comes to the front. A server without this endpoint answers 404: show the inbox only.

Parameters

This endpoint takes no parameters.

Request

curl "https://magiz.ai/api/agent/apps" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "apps": [
    {
      "id": "queue",
      "title": "Queue",
      "actions": [
        "next",
        "ticket",
        "walk_in",
        "sitting"
      ],
      "poll_seconds": 8
    },
    {
      "id": "bookings",
      "title": "Bookings",
      "actions": [
        "confirm",
        "decline",
        "cancel",
        "completed",
        "no_show"
      ],
      "poll_seconds": 30
    },
    {
      "id": "customers",
      "title": "Patients",
      "label": "patients",
      "actions": [
        "search",
        "profile"
      ],
      "poll_seconds": null
    }
  ]
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
429The route limit for this user was hit.

GET/api/agent/queue

The workspace's queue lines and the front desk of one line today: the number being served, who waits in the order they will be called, who missed their turn, the last few who left and the sitting's numbers.

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

Names and phone numbers are for staff only. A person limited to some branches sees only those branches' lines. Ask again every poll_seconds while the screen is open.

Parameters

ParameterTypeRequiredDescription
lineintegerOptionalQuery. The line to show. Defaults to the first live line.
sittingintegerOptionalQuery. The sitting to show. Defaults to the one going now, else the next one.

Request

curl "https://magiz.ai/api/agent/queue?line=7" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "lines": [
    {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live"
    }
  ],
  "desk": {
    "line": {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live",
      "timezone": "Asia/Kolkata"
    },
    "sittings": [
      {
        "id": 311,
        "slot": 0,
        "starts_at": "2026-10-12T04:30:00.000Z",
        "ends_at": "2026-10-12T07:30:00.000Z",
        "status": "running"
      },
      {
        "id": 312,
        "slot": 1,
        "starts_at": "2026-10-12T11:30:00.000Z",
        "ends_at": "2026-10-12T14:30:00.000Z",
        "status": "idle"
      }
    ],
    "sitting": {
      "id": 311,
      "day": "2026-10-12",
      "slot": 0,
      "status": "running",
      "taking": true,
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T07:30:00.000Z",
      "current_number": 4,
      "in_consult": true,
      "waiting": 2,
      "late_until": null,
      "note": null,
      "avg_seconds": 540,
      "version": 18
    },
    "called": {
      "id": 9014,
      "number": 4,
      "name": "Asma Test",
      "phone": "+919906010001",
      "status": "called",
      "source": "page",
      "arrived": true,
      "emergency": false,
      "misses": 0,
      "taken_at": "2026-10-12T04:41:09.000Z",
      "called_at": "2026-10-12T05:02:40.000Z"
    },
    "waiting": [
      {
        "id": 9015,
        "number": 5,
        "name": "Walk In Test",
        "phone": null,
        "status": "waiting",
        "source": "desk",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      },
      {
        "id": 9016,
        "number": 6,
        "name": null,
        "phone": "+919906010003",
        "status": "waiting",
        "source": "whatsapp",
        "arrived": false,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "skipped": [],
    "recent": [
      {
        "id": 9013,
        "number": 3,
        "name": "Imran Test",
        "phone": "+919906010002",
        "status": "done",
        "source": "page",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "summary": {
      "taken": 6,
      "seen": 3,
      "unseen": 0,
      "cancelled": 0,
      "open": 3,
      "wait_median": 14
    },
    "at": "2026-10-12T05:06:12.000Z"
  },
  "poll_seconds": 8
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such line, token or sitting in this workspace and the person's branches.
429The route limit for this user was hit.

POST/api/agent/queue/lines/{line}/next

Next: the patient with the doctor is marked as seen, or with skip as not here, and the next one is called. With ticket, that token is called instead.

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

Send the sitting's version from your last read. A press made on an older picture changes nothing and answers 409 with code stale, so two presses never move the line twice.

Parameters

ParameterTypeRequiredDescription
lineintegerRequiredPath. The line's id.
sittingintegerRequiredThe sitting's id, from desk.sitting.id.
versionintegerRequireddesk.sitting.version from your last read.
skipbooleanOptionaltrue when the patient who was called is not there.
ticketintegerOptionalA waiting or skipped token to call in place of the next in line.

Request

curl -X POST https://magiz.ai/api/agent/queue/lines/7/next \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "sitting": 311, "version": 17 }'

Response

{
  "ok": true,
  "lines": [
    {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live"
    }
  ],
  "desk": {
    "line": {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live",
      "timezone": "Asia/Kolkata"
    },
    "sittings": [
      {
        "id": 311,
        "slot": 0,
        "starts_at": "2026-10-12T04:30:00.000Z",
        "ends_at": "2026-10-12T07:30:00.000Z",
        "status": "running"
      },
      {
        "id": 312,
        "slot": 1,
        "starts_at": "2026-10-12T11:30:00.000Z",
        "ends_at": "2026-10-12T14:30:00.000Z",
        "status": "idle"
      }
    ],
    "sitting": {
      "id": 311,
      "day": "2026-10-12",
      "slot": 0,
      "status": "running",
      "taking": true,
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T07:30:00.000Z",
      "current_number": 4,
      "in_consult": true,
      "waiting": 2,
      "late_until": null,
      "note": null,
      "avg_seconds": 540,
      "version": 18
    },
    "called": {
      "id": 9014,
      "number": 4,
      "name": "Asma Test",
      "phone": "+919906010001",
      "status": "called",
      "source": "page",
      "arrived": true,
      "emergency": false,
      "misses": 0,
      "taken_at": "2026-10-12T04:41:09.000Z",
      "called_at": "2026-10-12T05:02:40.000Z"
    },
    "waiting": [
      {
        "id": 9015,
        "number": 5,
        "name": "Walk In Test",
        "phone": null,
        "status": "waiting",
        "source": "desk",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      },
      {
        "id": 9016,
        "number": 6,
        "name": null,
        "phone": "+919906010003",
        "status": "waiting",
        "source": "whatsapp",
        "arrived": false,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "skipped": [],
    "recent": [
      {
        "id": 9013,
        "number": 3,
        "name": "Imran Test",
        "phone": "+919906010002",
        "status": "done",
        "source": "page",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "summary": {
      "taken": 6,
      "seen": 3,
      "unseen": 0,
      "cancelled": 0,
      "open": 3,
      "wait_median": 14
    },
    "at": "2026-10-12T05:06:12.000Z"
  },
  "poll_seconds": 8
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such line, token or sitting in this workspace and the person's branches.
409stale: the line moved on another screen. Read it again and press once more.
409The token or the sitting cannot make this move now: code is ended, not_live, not_called, closed, full or stopped.
429The route limit for this user was hit.

POST/api/agent/queue/lines/{line}/tickets/{ticket}

One token: here (in the clinic, or back in line after a missed turn), emergency (sees next), cancel, done (seen, call nobody yet) or skip (not here, call nobody yet).

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

Each move goes on the line's timeline with who pressed, as on the dashboard's desk. The answer is the line's desk after the move, in the shape GET /api/agent/queue returns, with ok and a message.

Parameters

ParameterTypeRequiredDescription
lineintegerRequiredPath. The line's id.
ticketintegerRequiredPath. The token's id.
opstringRequiredhere, emergency, cancel, done or skip.

Request

curl -X POST https://magiz.ai/api/agent/queue/lines/7/tickets/9016 \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "op": "cancel" }'

Response

{
  "ok": true,
  "message": "Token 6 is cancelled.",
  "lines": [
    {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live"
    }
  ],
  "desk": {
    "line": {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live",
      "timezone": "Asia/Kolkata"
    },
    "sittings": [
      {
        "id": 311,
        "slot": 0,
        "starts_at": "2026-10-12T04:30:00.000Z",
        "ends_at": "2026-10-12T07:30:00.000Z",
        "status": "running"
      },
      {
        "id": 312,
        "slot": 1,
        "starts_at": "2026-10-12T11:30:00.000Z",
        "ends_at": "2026-10-12T14:30:00.000Z",
        "status": "idle"
      }
    ],
    "sitting": {
      "id": 311,
      "day": "2026-10-12",
      "slot": 0,
      "status": "running",
      "taking": true,
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T07:30:00.000Z",
      "current_number": 4,
      "in_consult": true,
      "waiting": 2,
      "late_until": null,
      "note": null,
      "avg_seconds": 540,
      "version": 18
    },
    "called": {
      "id": 9014,
      "number": 4,
      "name": "Asma Test",
      "phone": "+919906010001",
      "status": "called",
      "source": "page",
      "arrived": true,
      "emergency": false,
      "misses": 0,
      "taken_at": "2026-10-12T04:41:09.000Z",
      "called_at": "2026-10-12T05:02:40.000Z"
    },
    "waiting": [
      {
        "id": 9015,
        "number": 5,
        "name": "Walk In Test",
        "phone": null,
        "status": "waiting",
        "source": "desk",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      },
      {
        "id": 9016,
        "number": 6,
        "name": null,
        "phone": "+919906010003",
        "status": "waiting",
        "source": "whatsapp",
        "arrived": false,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "skipped": [],
    "recent": [
      {
        "id": 9013,
        "number": 3,
        "name": "Imran Test",
        "phone": "+919906010002",
        "status": "done",
        "source": "page",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "summary": {
      "taken": 6,
      "seen": 3,
      "unseen": 0,
      "cancelled": 0,
      "open": 3,
      "wait_median": 14
    },
    "at": "2026-10-12T05:06:12.000Z"
  },
  "poll_seconds": 8
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such line, token or sitting in this workspace and the person's branches.
409The token or the sitting cannot make this move now: code is ended, not_live, not_called, closed, full or stopped.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.

POST/api/agent/queue/lines/{line}/walk-in

Gives a token at the desk on the sitting on screen, also when the sitting is full or has stopped taking tokens. Name and phone are both optional.

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

Each move goes on the line's timeline with who pressed, as on the dashboard's desk. The answer is the line's desk after the move, in the shape GET /api/agent/queue returns, with ok and a message.

Parameters

ParameterTypeRequiredDescription
lineintegerRequiredPath. The line's id.
sittingintegerRequiredThe sitting's id, from desk.sitting.id.
namestringOptionalOptional. Up to 80 characters.
phonestringOptionalOptional. Up to 20 characters, with the country code.

Request

curl -X POST https://magiz.ai/api/agent/queue/lines/7/walk-in \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "sitting": 311, "name": "Walk In Test" }'

Response

{
  "ok": true,
  "message": "Token 5 added.",
  "ticket": {
    "id": 9015,
    "number": 5
  },
  "lines": [
    {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live"
    }
  ],
  "desk": {
    "line": {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live",
      "timezone": "Asia/Kolkata"
    },
    "sittings": [
      {
        "id": 311,
        "slot": 0,
        "starts_at": "2026-10-12T04:30:00.000Z",
        "ends_at": "2026-10-12T07:30:00.000Z",
        "status": "running"
      },
      {
        "id": 312,
        "slot": 1,
        "starts_at": "2026-10-12T11:30:00.000Z",
        "ends_at": "2026-10-12T14:30:00.000Z",
        "status": "idle"
      }
    ],
    "sitting": {
      "id": 311,
      "day": "2026-10-12",
      "slot": 0,
      "status": "running",
      "taking": true,
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T07:30:00.000Z",
      "current_number": 4,
      "in_consult": true,
      "waiting": 2,
      "late_until": null,
      "note": null,
      "avg_seconds": 540,
      "version": 18
    },
    "called": {
      "id": 9014,
      "number": 4,
      "name": "Asma Test",
      "phone": "+919906010001",
      "status": "called",
      "source": "page",
      "arrived": true,
      "emergency": false,
      "misses": 0,
      "taken_at": "2026-10-12T04:41:09.000Z",
      "called_at": "2026-10-12T05:02:40.000Z"
    },
    "waiting": [
      {
        "id": 9015,
        "number": 5,
        "name": "Walk In Test",
        "phone": null,
        "status": "waiting",
        "source": "desk",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      },
      {
        "id": 9016,
        "number": 6,
        "name": null,
        "phone": "+919906010003",
        "status": "waiting",
        "source": "whatsapp",
        "arrived": false,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "skipped": [],
    "recent": [
      {
        "id": 9013,
        "number": 3,
        "name": "Imran Test",
        "phone": "+919906010002",
        "status": "done",
        "source": "page",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "summary": {
      "taken": 6,
      "seen": 3,
      "unseen": 0,
      "cancelled": 0,
      "open": 3,
      "wait_median": 14
    },
    "at": "2026-10-12T05:06:12.000Z"
  },
  "poll_seconds": 8
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such line, token or sitting in this workspace and the person's branches.
409The token or the sitting cannot make this move now: code is ended, not_live, not_called, closed, full or stopped.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.

POST/api/agent/queue/lines/{line}/sittings/{sitting}

The sitting: pause, resume, stop new tokens, give tokens again, or end it.

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

Each move goes on the line's timeline with who pressed, as on the dashboard's desk. The answer is the line's desk after the move, in the shape GET /api/agent/queue returns, with ok and a message.

Parameters

ParameterTypeRequiredDescription
lineintegerRequiredPath. The line's id.
sittingintegerRequiredPath. The sitting's id.
opstringRequiredpause, resume, stop, open or end. Ending counts the patient in the room as seen and ends every token still waiting.

Request

curl -X POST https://magiz.ai/api/agent/queue/lines/7/sittings/311 \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "op": "pause" }'

Response

{
  "ok": true,
  "message": "The sitting is paused.",
  "lines": [
    {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live"
    }
  ],
  "desk": {
    "line": {
      "id": 7,
      "name": "Dr Sana Wani, room 1",
      "status": "live",
      "timezone": "Asia/Kolkata"
    },
    "sittings": [
      {
        "id": 311,
        "slot": 0,
        "starts_at": "2026-10-12T04:30:00.000Z",
        "ends_at": "2026-10-12T07:30:00.000Z",
        "status": "running"
      },
      {
        "id": 312,
        "slot": 1,
        "starts_at": "2026-10-12T11:30:00.000Z",
        "ends_at": "2026-10-12T14:30:00.000Z",
        "status": "idle"
      }
    ],
    "sitting": {
      "id": 311,
      "day": "2026-10-12",
      "slot": 0,
      "status": "running",
      "taking": true,
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T07:30:00.000Z",
      "current_number": 4,
      "in_consult": true,
      "waiting": 2,
      "late_until": null,
      "note": null,
      "avg_seconds": 540,
      "version": 18
    },
    "called": {
      "id": 9014,
      "number": 4,
      "name": "Asma Test",
      "phone": "+919906010001",
      "status": "called",
      "source": "page",
      "arrived": true,
      "emergency": false,
      "misses": 0,
      "taken_at": "2026-10-12T04:41:09.000Z",
      "called_at": "2026-10-12T05:02:40.000Z"
    },
    "waiting": [
      {
        "id": 9015,
        "number": 5,
        "name": "Walk In Test",
        "phone": null,
        "status": "waiting",
        "source": "desk",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      },
      {
        "id": 9016,
        "number": 6,
        "name": null,
        "phone": "+919906010003",
        "status": "waiting",
        "source": "whatsapp",
        "arrived": false,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "skipped": [],
    "recent": [
      {
        "id": 9013,
        "number": 3,
        "name": "Imran Test",
        "phone": "+919906010002",
        "status": "done",
        "source": "page",
        "arrived": true,
        "emergency": false,
        "misses": 0,
        "taken_at": "2026-10-12T04:41:09.000Z",
        "called_at": null
      }
    ],
    "summary": {
      "taken": 6,
      "seen": 3,
      "unseen": 0,
      "cancelled": 0,
      "open": 3,
      "wait_median": 14
    },
    "at": "2026-10-12T05:06:12.000Z"
  },
  "poll_seconds": 8
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such line, token or sitting in this workspace and the person's branches.
409The token or the sitting cannot make this move now: code is ended, not_live, not_called, closed, full or stopped.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.

GET/api/agent/bookings

One day's agenda on the workspace's clock: the bookings that hold time that day, with contact details and the changes each one allows now.

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

Cancelled and declined bookings free their time and are left out. Booking answers and internal notes are never returned. A person limited to some branches sees only those branches' bookings.

Parameters

ParameterTypeRequiredDescription
datestringOptionalQuery. YYYY-MM-DD in the workspace's time zone. Defaults to today.

Request

curl "https://magiz.ai/api/agent/bookings?date=2026-10-12" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "date": "2026-10-12",
  "today": "2026-10-12",
  "timezone": "Asia/Kolkata",
  "bookings": [
    {
      "id": 5521,
      "status": "confirmed",
      "kind": "appointment",
      "starts_at": "2026-10-12T04:30:00.000Z",
      "ends_at": "2026-10-12T05:00:00.000Z",
      "timezone": "Asia/Kolkata",
      "name": "Rafiq Test",
      "phone": "+919906040001",
      "email": null,
      "service": "Consultation",
      "staff": "Dr Sana Wani",
      "form": "Chinar Lane Clinic",
      "series": false,
      "actions": [
        "completed",
        "no_show",
        "cancel"
      ]
    },
    {
      "id": 5524,
      "status": "pending",
      "kind": "appointment",
      "starts_at": "2026-10-12T09:00:00.000Z",
      "ends_at": "2026-10-12T09:30:00.000Z",
      "timezone": "Asia/Kolkata",
      "name": "Mehak Test",
      "phone": "+919906040002",
      "email": null,
      "service": "Cleaning",
      "staff": "Dr Sana Wani",
      "form": "Chinar Lane Clinic",
      "series": false,
      "actions": [
        "confirm",
        "decline"
      ]
    },
    {
      "id": 5530,
      "status": "confirmed",
      "kind": "appointment",
      "starts_at": "2026-10-12T11:00:00.000Z",
      "ends_at": "2026-10-12T11:30:00.000Z",
      "timezone": "Asia/Kolkata",
      "name": "Owais Test",
      "phone": null,
      "email": null,
      "service": "Follow-up",
      "staff": "Dr Sana Wani",
      "form": "Chinar Lane Clinic",
      "series": true,
      "actions": [
        "cancel"
      ]
    }
  ],
  "poll_seconds": 30
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
429The route limit for this user was hit.

POST/api/agent/bookings/{booking}/status

Changes a booking as staff do on the dashboard: confirm or decline a waiting one, cancel a confirmed one, mark one that has started as done or did not come.

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

The change is written to the activity log, the customer gets the same message as from the dashboard, and workflows and webhooks hear the booking event.

Parameters

ParameterTypeRequiredDescription
bookingintegerRequiredPath. The booking's id.
actionstringRequiredconfirm, decline, cancel, completed or no_show. A booking's actions list says which apply now.
reasonstringOptionalOptional, with decline or cancel. Up to 250 characters.
scopestringOptionallater, with cancel: this booking and the later ones of its series.

Request

curl -X POST https://magiz.ai/api/agent/bookings/5521/status \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{ "action": "completed" }'

Response

{
  "ok": true,
  "message": "Marked as done",
  "bookings": [
    {
      "id": 5521,
      "status": "completed",
      "actions": []
    }
  ]
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such booking in this workspace and the person's branches.
409The booking cannot make this change now: code is booking_not_pending, booking_not_active, booking_not_started or booking_too_late.
422A field failed validation. The errors object names it.
429The route limit for this user was hit.
501not_available: this server cannot change bookings from the agent apps.

GET/api/agent/customers

Finds people by name, phone or email, the most recently changed first. Without q, the latest people.

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

Parameters

ParameterTypeRequiredDescription
qstringOptionalQuery. A name, phone or email. A phone search ignores spaces and the country prefix.

Request

curl "https://magiz.ai/api/agent/customers?q=asha" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "q": "asha",
  "people": [
    {
      "id": 812,
      "name": "Asha Test",
      "phone": "+919906011111",
      "email": "asha@example.test"
    }
  ],
  "total": 1,
  "label": "patients",
  "title": "Patients"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
429The route limit for this user was hit.

GET/api/agent/customers/{person}

A short profile: contact details, upcoming and recent bookings, and how many invoices are open while Invoices is on.

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

The person's note is never returned. A record merged into another answers with the one it became. open_invoices is null while Invoices is off.

Parameters

ParameterTypeRequiredDescription
personintegerRequiredPath. The person's id.

Request

curl "https://magiz.ai/api/agent/customers/812" \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Accept: application/json"

Response

{
  "person": {
    "id": 812,
    "name": "Asha Test",
    "phone": "+919906011111",
    "email": "asha@example.test",
    "guardian": null,
    "tags": [
      "regular"
    ]
  },
  "bookings": {
    "upcoming": [
      {
        "id": 5590,
        "at": "2026-10-20T05:30:00.000Z",
        "service": "Cleaning",
        "status": "confirmed"
      }
    ],
    "recent": [
      {
        "id": 5402,
        "at": "2026-09-28T06:00:00.000Z",
        "service": "Check-up",
        "status": "completed"
      }
    ]
  },
  "open_invoices": 1,
  "label": "patients",
  "title": "Patients"
}

Errors

StatusWhat causes it
401No valid token was sent.
403The account or the workspace has been suspended.
403app_off: the app is switched off for the workspace. A workspace manager can switch it on in Apps.
403The token is valid, but the user role does not grant this action.
404No such person in this workspace.
429The route limit for this user was hit.

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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.

Request

curl https://magiz.ai/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://magiz.ai",
  "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

StatusWhat causes it
404No active chatbot has that public key. An inactive chatbot answers the same way.
429The 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. The identity field says what this request proved about who is asking. Its state is one of verified, staff_view, expired, refused, client_area_no_client, staff_session, no_account, account_closed, module_error, not_configured, sign_in_page, signed_out or absent. It carries first_name only when this request's own identity token verified for a client, never for staff view.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_iduuidOptionalAn existing conversation to continue. Leave it out to start a new one.
metaobjectOptionalContext about the visitor and page. meta.visitor may carry name, email and phone from your pre-chat form.
identitystringOptionalA signed identity token from your own backend. It is verified before anything in it is trusted. Up to 4000 characters. A token whose sub or external_id is "0" is refused. A signed-in conversation continues without a token for 15 minutes after the last one that verified. After that it is set aside and a new conversation starts, and the same person's next valid token brings it back within 24 hours.
signed_outbooleanOptionalSend true when your page knows that nobody is signed in. If the conversation belongs to someone who signed in earlier, it is closed and a new one starts, so the next person at a shared computer never sees it.
identity_stateobjectOptionalWhy the page has no identity token, in codes only: {"v":1,"status":"client|staff|none","reason":"..."}. The reason is one of signed_out, staff, staff_view, no_account, account_closed, module_error or not_configured. It is used to word replies and never grants access to anything. Anything outside this shape is ignored.

Request

curl -X POST https://magiz.ai/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": "nadia@example.test" }
        }
      }'

Response

{
  "conversation_id": "6f0f1d84-2b6a-4a51-9f0e-5c2b3a7d8e91",
  "status": "bot",
  "handoff_state": "bot_active",
  "wait_remaining": null,
  "identity": { "state": "absent" },
  "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

StatusWhat causes it
404No active chatbot has that public key. An inactive chatbot answers the same way.
422A field failed validation. The errors object names it.
429The 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. The meta event also carries identity, the same object boot returns.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
messagestringRequiredThe visitor message. Up to 4000 characters, and it cannot be only whitespace.
conversation_iduuidOptionalAn existing conversation to continue. Leave it out to start a new one.
metaobjectOptionalContext about the visitor and page. meta.visitor may carry name, email and phone from your pre-chat form.
identitystringOptionalA signed identity token from your own backend. It is verified before anything in it is trusted. Up to 4000 characters. A token whose sub or external_id is "0" is refused. A signed-in conversation continues without a token for 15 minutes after the last one that verified. After that it is set aside and a new conversation starts, and the same person's next valid token brings it back within 24 hours.
signed_outbooleanOptionalSend true when your page knows that nobody is signed in. If the conversation belongs to someone who signed in earlier, it is closed and a new one starts, so the next person at a shared computer never sees it.
identity_stateobjectOptionalWhy the page has no identity token, in codes only: {"v":1,"status":"client|staff|none","reason":"..."}. The reason is one of signed_out, staff, staff_view, no_account, account_closed, module_error or not_configured. It is used to word replies and never grants access to anything. Anything outside this shape is ignored.

Request

curl -N -X POST https://magiz.ai/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","identity":{"state":"absent"}}

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

StatusWhat causes it
404No active chatbot has that public key. An inactive chatbot answers the same way.
422The message was only whitespace.
422A field failed validation. The errors object names it.
429The 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
conversation_iduuidRequiredThe conversation to close. It must belong to the visitor id you send.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
404No active chatbot has that public key. An inactive chatbot answers the same way.
422A field failed validation. The errors object names it.
429The 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, publicRate 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. A signed-in conversation answers {"reauth": true, "messages": []} once its last verified token is more than 15 minutes old. Call boot again with the page's identity token to carry on.

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
conversationIduuidRequiredPath. The conversation public id, a UUID.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
afterintegerOptionalQuery. Return only messages with an id greater than this.

Request

curl "https://magiz.ai/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

StatusWhat causes it
404No conversation with that id for this chatbot and visitor id.
422A field failed validation. The errors object names it.
429The 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, publicRate 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

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
conversationIduuidRequiredPath. The conversation public id, a UUID.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
message_idintegerRequiredThe assistant message being rated.
ratingintegerRequired1 for a thumbs up, -1 for a thumbs down, 0 to undo a previous vote.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
404The conversation was not found, or the message id is not an assistant message in it.
422A field failed validation. The errors object names it.
429The route limit for this IP address was hit.

POST/widget/{key}/conversations/{conversationId}/csat

Records a satisfaction score for the whole conversation.

Auth None, publicRate limit 10 requests every 1 min, per IP address

Parameters

ParameterTypeRequiredDescription
keystringRequiredPath. The chatbot public key, the same value used in the embed snippet.
conversationIduuidRequiredPath. The conversation public id, a UUID.
visitor_idstringRequiredThe id your widget assigns to a visitor and keeps for the session. Up to 100 characters.
scoreintegerRequiredSatisfaction score from 1 to 5.
commentstringOptionalFree-text comment. Up to 2000 characters.

Request

curl -X POST https://magiz.ai/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

StatusWhat causes it
404No conversation with that id for this chatbot and visitor id.
422A field failed validation. The errors object names it.
429The 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.

MethodEndpointWhy
POST/widget/{key}/uploadMultipart file upload, bound to the widget attachment flow and its storage rules.
POST/widget/{key}/request-humanOffline handoff intake. It sends email and WhatsApp alerts to the workspace, so it stays behind the widget own flow.
POST/widget/{key}/conversionsConversion beacon for the reporting pipeline, meaningful only alongside the widget tracking script.
POST/widget/{key}/trackBehaviour beacon for page, product and cart events. Opt-in per chatbot and shaped entirely by the widget.
POST/widget/{key}/presenceLive-visitor heartbeat. Its timing is tied to the widget beacon interval.
POST/widget/{key}/assistCo-pilot guidance. The payload is a snapshot of the visitor page produced by the widget.
GET/widget/{key}/attachments/{attachment}Streams one attachment to the visitor who owns the conversation. The address is issued by the widget and checked against that visitor.
POST/widget/{key}/chat/reveal/{token}Exchanges a one-time token for something the visitor asked for and nothing may keep, such as their own hosting password. Only the widget's own button calls it. A token works once, for 3 minutes, inside the signed-in conversation it was made for and only for the visitor who owns that conversation. Login details are shown only for a WHMCS install running module 1.6.0 or later. Any other request is refused (404, 410 or 422) and gets nothing.
POST/widget/{key}/chat/verificationSays whether a confirmation code sent by email is waiting in the visitor's conversation, the masked address it went to, and how many tries are left. Only the widget's own code box calls it, for the visitor who owns the conversation. Never returns the code.
POST/widget/{key}/chat/verification/{ref}/codeChecks one code typed in the widget's code box against the code emailed for a change. Five tries per request, then the request is closed. A right code is never stored or sent on: the widget then sends a plain message, which releases the change through the normal chat turn.
POST/widget/{key}/chat/verification/{ref}/resendSends a new code by the same email channel, replacing the last one. At most three times per request, thirty seconds apart, and within the merchant's own hourly limit. Answers with the masked address only.
POST/widget/{key}/chat/pay/{token}The pay button under a new client's first order (WHMCS module 1.8.0). Exchanges a token for WHMCS's own one-time sign-in to the account that conversation opened, on its invoice, made at that moment. Only the widget's own button calls it, from the conversation the token was made in and for the visitor who owns it, for two hours. Any other request is refused (404, 410 or 422) and gets nothing.

Need something that is not here?

Tell us what you are building and we will point you at the right endpoint, or add one.