Skip to content
MirageCHATEngagePublishGrow

Reseller API reference

Client workspaces · connect links · people · statementOne key for every clientUpdated

In short

The Reseller API lets your own software do what the Reseller menu does — create and close client workspaces, make connect links, add their people, set your name and logo, read your balance, statement and paid channels — and work inside any client workspace with one header, X-Workspace-Id. The rest of the API is on the developer overview.

Your two keys

Make both in Reseller › Settings, under Use the API — step by step. Each is shown once: copy it into your server. They are listed, and revoked, under Security › Developer › API Keys.

KeyMade inScopesWhat it does
Reseller keyReseller › Settings › Create reseller keyread · write · resellerThe /reseller/ routes — and, inside any client workspace, messages, conversations, contacts, webhooks and the workspace tools. It never posts.
Publishing keyReseller › Settings › Create publishing key, after ticking «Posts sent with this key are published on the selected accounts in my name.»publish · resellerPosts to every Instagram, Facebook and TikTok account of the client workspace X-Workspace-Id names, accounts connected later included. It reads no conversations.

The publishing key is made in the name of the person who ticked the confirmation. If that person leaves the team, it answers 403 consent_required: make a new one.

Work inside a client workspace

Send X-Workspace-Id with the id of a client workspace, on any route of the API but /reseller/. The request is then that workspace’s: its channels, conversations, contacts, webhooks, posts, package and holds. Without the header, the key acts as your own workspace. An id that is not one of yours is 404 workspace_not_found — never another reseller’s workspace, which would say it exists.

curl -X POST https://miragechat.io/api/ext/v1/messages \
  -H "Authorization: Bearer mck_live_…" \
  -H "X-Workspace-Id: 1304" \
  -H "Content-Type: application/json" \
  -d '{"account_id": 77, "to": "+15551234567", "text": "Your appointment is at 10:30."}'

The rate limit counts each client workspace on its own: about 300 requests a minute per key and workspace (the Publishing API: 60), and 3,000 a minute for the key in all. One client cannot spend another’s minute.

Endpoints

Base URL https://miragechat.io/api/ext/v1. Every route needs the reseller scope, with read for a GET and write for a change. A path {id} that is not one of your client workspaces is 404 workspace_not_found.

MethodPathScopeWhat it does
GET/reseller/meread · resellerYour account: status, prices, balance, what a month costs at today’s channels, and what falls due in the next 7 days.
GET/reseller/workspacesread · resellerYour client workspaces, newest first. include_closed=0 leaves the closed ones out; external_id finds one by your reference.
POST/reseller/workspaceswrite · resellerCreate a client workspace: name, timezone, external_id, return_url. With return_url, the answer carries its connect link. Send external_id and a retry is safe: the same one again is 409 external_id_taken with the workspace_id, never a second workspace.
GET/reseller/workspaces/{id}read · resellerOne client workspace.
PATCH/reseller/workspaces/{id}write · resellerRename it, or change your reference (external_id; null clears it).
DELETE/reseller/workspaces/{id}write · resellerClose it: read-only at once, its channels switched off, its data kept for 90 days.
POST/reseller/workspaces/{id}/connect-linkwrite · resellerA new connect link with your name and logo: return_url, and hours from 1 to 168 (24 when left out; another number is 400).
POST/reseller/workspaces/{id}/connect-link/revokewrite · resellerEvery open connect link of the workspace stops working at once.
GET/reseller/workspaces/{id}/usersread · resellerThe people who sign in to it: role, switched off or not, last sign-in.
POST/reseller/workspaces/{id}/userswrite · resellerAdd a person: email, password, role (admin or agent) and name. Nothing is emailed to them.
PATCH/reseller/workspaces/{id}/users/{userId}write · resellerSwitch a person off or on, or change their role, password or name.
GET/reseller/channelsread · resellerEvery paid channel of your client workspaces, with paid_until and monthly_usd — to bill your own clients by.
GET/reseller/statementread · resellerWhat was taken from your balance, newest first: limit (1 to 500, 100 when left out; another number is 400), and before for older lines — next_before is null on the last page.
GET/reseller/settingsread · resellerYour name and logo on the connect page.
PATCH/reseller/settingswrite · resellerChange display_name and logo_url (an https:// address).

Client workspaces

POST /reseller/workspaces takes a name (required), a timezone (a zone name such as Europe/London), your own reference in external_id (two of your workspaces cannot share one: 409 external_id_taken, with the workspace_id that has it — so a retry with the same external_id never makes a second workspace), and a return_url. name and external_id are text of at most 120 characters (400 invalid_request otherwise — they are not cut); an external_id of "" or null is none. With a return_url, the answer also carries connect_url and connect_expires_at; a link that could not be made is said in connect_error, and the workspace is made all the same — make the link later.

curl -X POST https://miragechat.io/api/ext/v1/reseller/workspaces \
  -H "Authorization: Bearer mck_live_…" \
  -H "Content-Type: application/json" \
  -d '{"name": "Seaside Villa", "timezone": "Europe/London", "external_id": "client-42",
       "return_url": "https://your-app.example.com/clients/42"}'

201 Created
{
  "workspace": {
    "id": 1304, "name": "Seaside Villa", "slug": "seaside-villa-3fa91c", "external_id": "client-42",
    "timezone": "Europe/London", "created_at": "2026-10-15T09:12:03.000Z", "closed_at": null,
    "status": "no_channels", "channels": [], "chats_30d": 0, "monthly_usd": 0
  },
  "connect_url": "https://miragechat.io/connect/c_…",
  "connect_expires_at": "2026-10-16T09:12:03.000Z"
}

A workspace carries id, name, slug, external_id, timezone, created_at, closed_at, status (active, no_channels or closed), channels (its connected accounts), chats_30d and monthly_usd. GET /reseller/workspaces lists closed ones too, unless include_closed=0; external_id=client-42 finds yours.

DELETE /reseller/workspaces/{id} closes it: read-only at once, its channels switched off — each one told to your webhooks as account.disconnected — and its data kept for 90 days. It answers the workspace with channels_switched_off and delete_after_days. A closed workspace is not renamed (409 workspace_closed) and takes no new link or person.

A connect link opens a page with your name and logo, where your client connects WhatsApp, Instagram and a Facebook Page without a MirageCHAT account. It works for hours (1 to 168; 24 when left out). Each call makes a new link, and the earlier ones keep working until they expire — POST …/connect-link/revoke stops every open link of the workspace at once and answers how many: { "workspace_id": 1304, "revoked": 2 }.

curl -X POST https://miragechat.io/api/ext/v1/reseller/workspaces/1304/connect-link \
  -H "Authorization: Bearer mck_live_…" \
  -H "Content-Type: application/json" \
  -d '{"return_url": "https://your-app.example.com/clients/42", "hours": 48}'

201 Created
{ "workspace_id": 1304, "url": "https://miragechat.io/connect/c_…", "expires_at": "2026-10-17T09:20:00.000Z" }

People

Your client’s staff sign in only if you add them. POST …/users takes an email, a password you set, a role (admin or agent; agent when left out) and a name. We email them nothing — no invitation, no confirmation. One address opens one workspace: an address that already signs in anywhere is 409 email_taken. An agent answers the channels connected when they are added.

curl -X POST https://miragechat.io/api/ext/v1/reseller/workspaces/1304/users \
  -H "Authorization: Bearer mck_live_…" \
  -H "Content-Type: application/json" \
  -d '{"email": "ana@seasidevilla.example", "password": "…", "role": "admin", "name": "Ana Lee"}'

201 Created
{ "user": { "id": 5521, "name": "Ana Lee", "email": "ana@seasidevilla.example", "role": "admin",
           "disabled": false, "last_login": null, "created_at": "2026-10-15T09:25:41.000Z" } }

PATCH …/users/{userId} takes disabled, role, password and name. Switched off, a person is signed out at once and their remembered devices are forgotten; a new role ends their sessions too; a new password is not announced to anyone. An owner or a manager is not yours to re-role (409 role_not_changeable). The list never shows the workspace’s own system account.

Balance, statement and channels

  • GET /reseller/me — status, prices (platform_usd, channel_usd), balance_usd, monthly_usd, channels, workspaces (open and total), platform_paid_until, grace_until, and what falls due in the next 7 days: due_soon, due_soon_usd and short_usd — what your balance lacks to cover it.
  • GET /reseller/statement — every charge, newest first: id, kind, workspace_id, workspace_name, platform, amount, period_from, period_to, ledger_reference, created_at. Send next_before back as before for older lines; it is null on the last page. limit is 1 to 500 (100 when left out).
  • GET /reseller/channels — every channel of your client workspaces you have paid for, with the account it is now, connected, paid_until and monthly_usd at your price. A connected channel renews on paid_until; a disconnected one keeps its month and does not renew. It lists channels that are connected or inside a paid month; include_ended=1 adds the ones whose month ran out. workspace_id filters, limit and cursor page.
curl "https://miragechat.io/api/ext/v1/reseller/channels?workspace_id=1304" \
  -H "Authorization: Bearer mck_live_…"

200 OK
{
  "data": [
    { "id": 731, "workspace_id": 1304, "workspace_name": "Seaside Villa", "external_id": "client-42",
      "workspace_closed": false, "platform": "whatsapp", "account_id": 77, "account_name": "Seaside Villa",
      "connected": true, "paid_until": "2026-11-15T09:40:00.000Z", "monthly_usd": 1.25 }
  ],
  "next_cursor": null
}

Your name and logo

GET and PATCH /reseller/settings read and change display_name and logo_url — what your clients see on the connect page. The logo is an https:// address (400 invalid_logo_url otherwise); an empty name shows your workspace’s own. Prices are set by our team, not here.

One webhook for every client

An endpoint with include_clients: true also receives every event of every client workspace, each with the workspace_id it came from. Make it with the reseller key and without X-Workspace-Id (403 reseller_only otherwise), choosing your events — the posts of your client workspaces arrive too, if it takes post.*. Or add one in Reseller › Settings: it takes message.received, message.sent, conversation.created, conversation.closed, account.connected and account.disconnected. The delivery’s tenant_id is your own workspace’s; account.* events add your external_id.

curl -X POST https://miragechat.io/api/ext/v1/webhooks \
  -H "Authorization: Bearer mck_live_…" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://your-app.example.com/hooks/mirage", "include_clients": true,
       "events": ["message.received", "conversation.created", "account.connected", "post.published"]}'

Signatures, retries and every event: Webhooks on the developer overview.

When your account is paused

While your balance cannot cover what falls due in the next 7 days, we email you — at most once a day. A renewal that still cannot be paid gets one day of grace; then your account and every client workspace are paused until the money arrives.

  • Refused with 402 on_hold and billing_url: whatever adds to your workspaces — a new client workspace, a rename, a connect link, a person added, switched back on or changed, your settings.
  • Always works: reading, closing a client workspace, revoking its links, switching a person off.
  • Inside a client workspace, writes are refused with 402 too (holds); reads still answer, and messages keep arriving.

Errors

A refusal is { "error": "<code>", "code": "<code>", "message": "…" } — error and code are the same word.

CodeHTTPMeaning
missing_api_key · invalid_api_key401No key, or a wrong, revoked or expired one.
insufficient_scope403A publishing key, or a key without read (for a GET) or write (for a change) — required names it.
reseller_scope_required403The key has no reseller scope. Use a key made in Reseller › Settings.
not_a_reseller403The key’s workspace is not a reseller now.
workspace_not_found · user_not_found404Not one of your client workspaces, or not a person of that workspace.
invalid_request · not_editable400A field is missing or wrong, or cannot be changed here — the message names it.
invalid_email · invalid_role · password_required · weak_password400A person’s details. weak_password adds password_failed and password_rules.
invalid_return_url · invalid_logo_url · invalid_cursor400An address that is not https://, or a cursor this list did not give.
external_id_taken · email_taken409Your reference names another client workspace, or the address already signs in to a MirageCHAT workspace.
workspace_closed · role_not_changeable409The workspace is closed (it is read-only), or the person’s role is not yours to change.
on_hold402Your account is paused: a renewal was not paid after its day of grace. billing_url says where to add money.
internal_error500Something failed on our side, and nothing was changed. Try again in a moment.

What it does not do

YouTube data is not available through the API. YouTube’s rules for apps (YouTube API Services Developer Policies) do not allow it: no YouTube conversation, comment, automation or number is read through the API, and nothing is posted to YouTube with it — platform=youtube answers 400 platform_not_available, a YouTube account in POST /posts answers 422 unsupported_by_platform. Post to YouTube from Instant Post in MirageCHAT.

  • AI in a client workspace. Client workspaces have no AI assistant, so POST /ai/reply answers 402 module_required there.
  • Your prices and your partner account are set by our team.
  • Reopening a closed client workspace is not possible from the API.
  • Connecting channels. The connect link covers WhatsApp, Instagram and a Facebook Page; Telegram, website chat, SMS, TikTok, YouTube and Google are connected inside the client workspace, under Channels.

Try MirageCHAT free for 14 days

No credit card is required, and then Free — 2 accounts, the inbox and Instant Post. Provider charges such as WhatsApp or SMS stay on your own provider account.

Start free trial