SDK & Widget · Mobile

SDK REST API

The HTTP endpoints behind every Inboxi chat client. Use them to build a native chat in Flutter, Swift, Kotlin or anything else.

All endpoints live under https://inboxi.app/api/widget/sdk, accept and return JSON, and answer with "success": true on success. init uses your API key; every other endpoint uses the session token it returns (see Authentication).

EndpointAuthPurpose
POST /sdk/initX-API-KeyOpen a session, get the widget config
POST /sdk/identifyBearerAttach user details, get the chat ID
POST /sdk/messagesBearerSend a message
GET /sdk/messages/:chatIdBearerMessage history
GET /sdk/conversationsBearerThe visitor's conversations
POST /sdk/device-tokenBearerRegister a push token

Init

POST/api/widget/sdk/initOpen an SDK session

Requires an API key with the widget permission. Returns a 24-hour session token and the widget appearance.

ParameterTypeRequiredDescription
appIdstringoptionalYour App ID. The workspace is taken from the API key; send it anyway for clarity.
platformstringoptionalreact_native | flutter | ios | android.
appVersionstringoptionalYour app version, for your own diagnostics.
userIdstringoptionalYour user ID. Becomes the visitorId so the user gets the same conversation on every session. Omit for anonymous visitors (an sdk_… ID is generated).
widgetIdstringoptionalIf your workspace runs several widgets, the one this session belongs to. Also accepted as context.widgetId. Defaults to your first active website widget.
curl -X POST https://inboxi.app/api/widget/sdk/init \
  -H "X-API-Key: inx_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "appId": "YOUR_APP_ID", "platform": "android", "appVersion": "1.4.0", "userId": "user_123" }'
200 OK
{
  "success": true,
  "sessionToken": "eyJhbGciOiJIUzI1NiIs...",
  "visitorId": "user_123",
  "socketUrl": "https://inboxi.app",
  "organizationId": 1234,
  "config": {
    "primaryColor": "#6366f1",
    "headerColor": "#0f172a",
    "headerTextColor": "#ffffff",
    "backgroundColor": "#f0f2f5",
    "botMessageBackgroundColor": "#ffffff",
    "botMessageTextColor": "#1f2937",
    "userMessageTextColor": "#ffffff",
    "welcomeMessage": "Hi! How can we help?",
    "businessName": "Your Business",
    "logoUrl": "https://...",
    "language": "en",
    "aiEnabled": true
  }
}

Keep visitorId and organizationId: the socket needs both.

Identify

POST/api/widget/sdk/identifyAttach user details to the session

Call after your user logs in. Inboxi finds or creates the visitor's conversation, matching on email or phone first so the same person on a new device lands on the same contact.

ParameterTypeRequiredDescription
namestringrequiredDisplay name shown in the inbox.
userIdstringoptionalYour user ID, stored on the contact as the external user ID.
emailstringoptionalEmail address.
phonestringoptionalPhone in international format.
dataobjectoptionalCustom fields shown to your team (plan, city, last order…).
curl -X POST https://inboxi.app/api/widget/sdk/identify \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "userId": "user_123", "name": "Mohamed Ali", "email": "mohamed@example.com", "phone": "+201234567890", "data": { "plan": "premium" } }'
200 OK
{ "success": true, "visitorId": "user_123", "chatId": 456, "isNewChat": false }

Send a message

POST/api/widget/sdk/messagesSend a visitor message over REST

Works without a socket, which makes it the right choice for background sends and simple clients. The message appears in the inbox, notifies your team, and triggers the AI agent if the widget has AI enabled. A resolved conversation is reopened.

ParameterTypeRequiredDescription
textstringoptionalMessage text. Required unless mediaUrl is set; becomes the caption when it is.
mediaUrlstringoptionalPublic https URL of an image, video, audio or document you uploaded yourself. A message whose text is only such a link is treated as media too.
mediaTypestringoptionalimage | video | audio | document | file. Detected from the URL when omitted.
mimetypestringoptionalMIME type of the attachment.
curl -X POST https://inboxi.app/api/widget/sdk/messages \
  -H "Authorization: Bearer $SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Hello, I need help with my order" }'
200 OK
{ "success": true, "messageId": 789, "chatId": 456, "timestamp": "2026-04-09T12:00:00.000Z" }
The REST response confirms delivery of the visitor's message only. The reply (from the AI or your team) arrives on the socket as widget_message, or you can poll the history endpoint.

Message history

GET/api/widget/sdk/messages/:chatIdMessages in one conversation
ParameterTypeRequiredDescription
chatIdinteger (path)requiredFrom identify, send or conversations. Must belong to the session visitor.
pageintegeroptionalPage number, default 1.
limitintegeroptionalPage size, default 50, maximum 100.
200 OK
{
  "success": true,
  "messages": [
    { "id": 1, "content": "Hello", "sender": "customer", "timestamp": "...", "mediaUrl": null, "mediaType": null },
    { "id": 2, "content": "Hi! How can I help?", "sender": "agent", "timestamp": "...", "mediaUrl": null, "mediaType": null }
  ],
  "pagination": { "page": 1, "limit": 50, "total": 2, "totalPages": 1 }
}

Messages are ordered oldest first. sender is customer, agent or system. mediaUrl is always an absolute URL you can load directly.

Conversations

GET/api/widget/sdk/conversationsAll conversations of the session visitor
200 OK
{
  "success": true,
  "conversations": [
    {
      "id": 456,
      "customerName": "Mohamed Ali",
      "lastMessage": "Hi! How can I help?",
      "lastMessageAt": "2026-04-09T12:00:05.000Z",
      "status": "open",
      "unreadCount": 0
    }
  ]
}

Ordered by latest activity. Conversations merged into this visitor from another device are included.

Register a device token

POST/api/widget/sdk/device-tokenRegister an FCM / APNs token for push
ParameterTypeRequiredDescription
tokenstringrequiredThe device push token.
platformstringrequiredios or android.
200 OK
{ "success": true, "deviceTokenId": 77, "isNew": true }

A token is unique: registering a token that already exists moves it to the current visitor and reactivates it. Call this after every init and whenever Firebase rotates the token.