Connect your systems to Inboxy — send every kind of WhatsApp message, create templates, campaigns and scheduled messages, and manage contacts, conversations, leads, tickets, orders, products and webhooks — with one API token.
The /public routes return this success shape; every other route returns its own JSON object. Every error on every route called with a token has the second shape, with any extra fields under details.
The body or query is invalid. The message says which field.
401
UNAUTHORIZED
Missing, revoked or expired token, or a route keys cannot call.
403
INSUFFICIENT_PERMISSIONS
The token lacks the scope this route needs.
403
SUBSCRIPTION_NOT_ACTIVE · FORBIDDEN
The plan or channel does not allow this action.
404
NOT_FOUND
The resource is not in your company.
409
CONFLICT
The resource is not in a state that allows this (for example a template missing its media).
429
TOO_MANY_REQUESTS
60 requests per minute per token.
500
INTERNAL_ERROR
Our fault. Retry later; quote the X-Request-Id header to support.
Webhooks
Register a public HTTPS URL and Inboxy calls it the moment something happens: messages on every channel, button taps, delivery and read receipts, tickets, leads, and every order change from connected stores.
Subscribe to exact event names, "*" for everything, or a prefix like "whatsapp.*".
Any 2xx within 30 seconds is a success. Otherwise we retry 3 times by default (up to 9) with exponential backoff starting at 1 second.
After 50 consecutive failures (configurable) the webhook pauses and your admins are notified. Redeliver the last 7 days of failures with /replay.
A retry can deliver the same event twice — deduplicate on the payload id, and keep the larger sequence when two events about the same entity arrive out of order. version is the payload contract (v1); the schemas are at GET /webhooks/contract.
Every request carries X-Inboxy-Timestamp and X-Inboxy-Signature = sha256=HMAC_SHA256(secret, "timestamp.body"). Get the secret from GET /webhooks/:id/secret.
import crypto from 'node:crypto';
// Use the raw request body — not a re-serialized object.
export function isFromInboxy(rawBody, headers, secret) {
const timestamp = headers['x-inboxy-timestamp'];
const received = headers['x-inboxy-signature'] || '';
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false; // 5-minute window
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
return received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
}
Events (77)
message.*
message.received
When a new message is received
message.sent
When a message is sent
message.status_updated
When an outbound message is delivered, read or fails
contact.*
contact.created
When a new contact is created
contact.updated
When a contact is updated
conversation.*
conversation.opened
When a conversation is opened
conversation.closed
When a conversation is closed
conversation.assigned
When a conversation is assigned to an agent
conversation.created
A new conversation starts on any channel
conversation.resolved
A conversation is closed (legacy event name: Inboxy has no resolved state)
order.*
order.created
When an order is created
order.updated
When an order status changes
order.completed
When an order is completed
order.cancelled
When an order is cancelled
campaign.*
campaign.started
When a campaign starts running
campaign.completed
When a campaign finishes
agent.*
agent.response
When an AI agent responds
whatsapp.*
whatsapp.message.received
WhatsApp: a text message arrives
whatsapp.media.received
WhatsApp: an image, video, audio, document or sticker arrives
whatsapp.voice.received
WhatsApp: a voice note arrives
whatsapp.location.received
WhatsApp: the customer shares a location
whatsapp.contact_card.received
WhatsApp: the customer shares a contact card
whatsapp.reaction.received
WhatsApp: the customer reacts to a message
whatsapp.button.clicked
WhatsApp: the customer taps a reply button
whatsapp.list.selected
WhatsApp: the customer picks a list row
whatsapp.template.reply
WhatsApp: the customer taps a template quick-reply button
whatsapp.flow.completed
WhatsApp: the customer submits a WhatsApp Flow
whatsapp.order.placed
WhatsApp: the customer sends a cart from the catalog
whatsapp.referral.received
WhatsApp: a conversation starts from a click-to-WhatsApp ad
whatsapp.message.status_changed
WhatsApp: an outbound message is sent, delivered, read or fails
instagram.*
instagram.message.received
Instagram: a DM arrives
instagram.media.received
Instagram: a DM with media arrives
instagram.reaction.received
Instagram: the customer reacts to a message
instagram.button.clicked
Instagram: the customer taps a button or quick reply
instagram.story.reply
Instagram: the customer replies to your story
instagram.story.mention
Instagram: the customer mentions you in their story
instagram.referral.received
Instagram: a conversation starts from an ad or link
instagram.first.inbound
Instagram: a customer's first message ever
messenger.*
messenger.message.received
Messenger: a message arrives
messenger.media.received
Messenger: a message with media arrives
messenger.voice.received
Messenger: a voice message arrives
messenger.location.received
Messenger: the customer shares a location
messenger.reaction.received
Messenger: the customer reacts to a message
messenger.button.clicked
Messenger: the customer taps a button or quick reply
messenger.template.reply
Messenger: the customer answers a template
messenger.referral.received
Messenger: a conversation starts from an ad or m.me link
messenger.first.inbound
Messenger: a customer's first message ever
telegram.*
telegram.message.received
Telegram: a message arrives
telegram.media.received
Telegram: a message with media arrives
telegram.location.received
Telegram: the customer shares a location
telegram.command.received
Telegram: the customer sends a /command
telegram.button.clicked
Telegram: the customer taps an inline button
telegram.first.inbound
Telegram: a customer's first message ever
widget.*
widget.chat.opened
Website chat: a visitor opens the chat
widget.message.received
Website chat: a visitor sends a message
widget.media.received
Website chat: a visitor sends a file
widget.button.clicked
Website chat: a visitor taps a button
widget.form.submitted
Website chat: a visitor submits a form
widget.first.inbound
Website chat: a visitor's first message ever
lead.*
lead.created
A lead is created
ticket.*
ticket.created
A support ticket is created
ticket.assigned
A ticket is assigned
ticket.status_changed
A ticket changes status
task.*
task.created
A task is created
task.assigned
A task is assigned
task.completed
A task is completed
web_event.*
web_event.received
Your website sends a tracked event (web events API)
curl -X GET "https://api.inboxy.chat/api/v1/whatsapp/templates" \
-H "Authorization: Bearer inboxy_your_token"
POST/api/v1/whatsapp/templatestemplates:write
Create a WhatsApp template and submit it to Meta for review
Requires templates:write permission.
Body
namerequired
string
Lowercase letters, digits and underscores. Unique per language.
categoryrequired
MARKETING | UTILITY | AUTHENTICATION
languagerequired
string
Meta language code.
templateType
STANDARD | CAROUSEL | LIMITED_TIME_OFFER
headerType
NONE | TEXT | IMAGE | VIDEO | DOCUMENT
headerText
string
TEXT headers: up to 60 characters, at most one {{1}}.
headerExample
string
TEXT headers: sample for {{1}}. IMAGE/VIDEO/DOCUMENT headers: the media handle from POST /api/v1/whatsapp/media/upload-for-template.
headerMediaUrl
string
Media headers: the public URL of the same file, stored so every send attaches it automatically.
bodyTextrequired
string
Up to 1,024 characters. Variables are {{1}}, {{2}}, … in order.
bodyExamples
string[]
One sample value per body variable, in order. Meta reviews the template with these.
footerText
string
Up to 60 characters, no variables.
buttons
object[]
Up to 10 buttons.
carouselCards
object[]
CAROUSEL templates: 2–10 cards, each with a media header, body and buttons.
ltoText
string
LIMITED_TIME_OFFER: the offer headline, up to 16 characters. The offer also needs exactly one URL button in `buttons`.
ltoExpiration
string
LIMITED_TIME_OFFER: when the offer ends.
ltoCouponCode
string
LIMITED_TIME_OFFER: coupon shown on a copy-code button, placed before the URL button.
authSecurityDisclaimer
boolean
AUTHENTICATION: add "Do not share this code" (default true).
authExpirationMinutes
number
AUTHENTICATION: code lifetime shown to the customer.
variableMapping
object
Required when bodyText has variables: one entry per variable number, saying where the value comes from at send time. Types: `static` (value used as-is), `contact_field` (firstName, lastName, name, email, phone), `custom_field` (a contact custom-field key), `order_field` (last.order.total, last.order.product, last.order.status, last.order.date, last.order.shipping_address, last.order.tracking_number), `web_event_field` (a path in the triggering web event).
WhatsApp (Meta) message templates that are not archived, newest first. Filter by status, category, language or name. Requires templates:read permission.
Query parameters
limit
integer
Page size, 1-100 (default 20).
pageSize
integer
Deprecated alias of `limit`.
cursor
string
The `meta.nextCursor` of the previous page. Opaque.
page
integer
Removed in favour of `cursor`. `page=1` is accepted; any other value is refused with 400.
status
approved | pending | rejected | paused | disabled
category
utility | marketing | authentication
language
string
For example `ar` or `en_US`.
search
string
Template name contains.
curl -X GET "https://api.inboxy.chat/api/v1/public/templates" \
-H "Authorization: Bearer inboxy_your_token"
WhatsApp analytics
GET/api/v1/whatsapp/statsanalytics:read
WhatsApp message and conversation totals
Requires analytics:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/whatsapp/stats" \
-H "Authorization: Bearer inboxy_your_token"
curl -X GET "https://api.inboxy.chat/api/v1/whatsapp/campaigns" \
-H "Authorization: Bearer inboxy_your_token"
POST/api/v1/whatsapp/campaignscampaigns:write
Create a campaign
Requires campaigns:write permission.
Body
namerequired
string
templateIdrequired
string
An APPROVED template id (GET /api/v1/whatsapp/templates).
audiencerequired
object
Who receives the campaign. `ALL`: every opted-in contact. `TAGS`: contacts with any of `tagIds`. `CONTACTS`: exactly `contactIds` (max 5,000). `IMPORT_BATCH`: the `batchId` returned by import-audience.
templateComponents
object[]
Meta template components; omit to use the template’s saved variable mapping.
scheduledAt
string
Omit to create a draft; run it with POST /campaigns/:id/run.
curl -X GET "https://api.inboxy.chat/api/v1/whatsapp/campaigns/{id}" \
-H "Authorization: Bearer inboxy_your_token"
PUT/api/v1/whatsapp/campaigns/{id}campaigns:write
Update a draft or scheduled campaign
Requires campaigns:write permission.
Path parameters
idrequired
string
Body
name
string
templateId
string
audience
object
Who receives the campaign. `ALL`: every opted-in contact. `TAGS`: contacts with any of `tagIds`. `CONTACTS`: exactly `contactIds` (max 5,000). `IMPORT_BATCH`: the `batchId` returned by import-audience.
Who receives the campaign. `ALL`: every opted-in contact. `TAGS`: contacts with any of `tagIds`. `CONTACTS`: exactly `contactIds` (max 5,000). `IMPORT_BATCH`: the `batchId` returned by import-audience.
The event that starts the workflow — any webhook platform event name, e.g. "whatsapp.message.received", "ecommerce.cart.abandoned", "web_event.received".
Each node: `{ id, type, position?, label?, config?, version? }`. `type` is a registered node type (e.g. "whatsapp.send.text", "time.delay", "ticket.create"); `config` is validated per type on publish. Max 500. Easiest start: export a workflow built in the dashboard (GET …/:workflowId/export) and edit it.
edgesrequired
object[]
Each edge: `{ id, source, target, sourceHandle? }` referencing node ids. Max 1000.
The event that starts the workflow — any webhook platform event name, e.g. "whatsapp.message.received", "ecommerce.cart.abandoned", "web_event.received".
Each node: `{ id, type, position?, label?, config?, version? }`. `type` is a registered node type (e.g. "whatsapp.send.text", "time.delay", "ticket.create"); `config` is validated per type on publish. Max 500. Easiest start: export a workflow built in the dashboard (GET …/:workflowId/export) and edit it.
edgesrequired
object[]
Each edge: `{ id, source, target, sourceHandle? }` referencing node ids. Max 1000.
curl -X GET "https://api.inboxy.chat/api/v1/ecommerce/customers" \
-H "Authorization: Bearer inboxy_your_token"
GET/api/v1/ecommerce/customers/{id}ecommerce:read
Get a store customer with orders
Requires ecommerce:read permission.
Path parameters
idrequired
string
curl -X GET "https://api.inboxy.chat/api/v1/ecommerce/customers/{id}" \
-H "Authorization: Bearer inboxy_your_token"
Webhooks
GET/api/v1/webhooks/eventswebhooks:read
List webhook event types
Requires webhooks:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/webhooks/events" \
-H "Authorization: Bearer inboxy_your_token"
GET/api/v1/webhookswebhooks:read
List webhooks
Requires webhooks:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/webhooks" \
-H "Authorization: Bearer inboxy_your_token"
POST/api/v1/webhookswebhooks:write
Register a webhook
Requires webhooks:write permission.
Body
namerequired
string
Webhook name.
urlrequired
string
HTTPS endpoint to receive events. Must be a public, non-private-network URL.
eventsrequired
string[]
Events to receive: exact names from GET /api/v1/webhooks/events, "*" for everything, or a prefix wildcard such as "whatsapp.*", "ecommerce.order.*" or "ticket.*".
maxRetries
number
Max delivery retry attempts.
fieldExclusions
string[]
Dot-separated payload paths to omit from delivered payloads (max 20).
consecutiveFailureThreshold
number
Consecutive failures (5-1000) before the webhook auto-pauses.
curl -X GET "https://api.inboxy.chat/api/v1/webhooks/{webhookId}" \
-H "Authorization: Bearer inboxy_your_token"
PUT/api/v1/webhooks/{webhookId}webhooks:write
Update a webhook
Requires webhooks:write permission.
Path parameters
webhookIdrequired
string
Body
name
string
Webhook name.
url
string
HTTPS endpoint to receive events.
events
string[]
Events to receive: exact names from GET /api/v1/webhooks/events, "*" for everything, or a prefix wildcard such as "whatsapp.*", "ecommerce.order.*" or "ticket.*".
status
ACTIVE | PAUSED | FAILED
Webhook status.
maxRetries
number
Max delivery retry attempts.
fieldExclusions
string[]
Dot-separated payload paths to omit from delivered payloads (max 20).
consecutiveFailureThreshold
number
Consecutive failures (5-1000) before the webhook auto-pauses.
The Inboxy catalog (products made in Inboxy and synced from stores into it), newest first. Requires products:read permission.
Query parameters
limit
integer
Page size, 1-100 (default 20).
pageSize
integer
Deprecated alias of `limit`.
cursor
string
The `meta.nextCursor` of the previous page. Opaque.
page
integer
Removed in favour of `cursor`. `page=1` is accepted; any other value is refused with 400.
search
string
Name or SKU contains.
categoryId
string
isActive
true | false
curl -X GET "https://api.inboxy.chat/api/v1/public/products" \
-H "Authorization: Bearer inboxy_your_token"
GET/api/v1/public/products/{id}products:read
Get a product
One catalog product. Requires products:read permission.
Path parameters
idrequired
string
Resource id
curl -X GET "https://api.inboxy.chat/api/v1/public/products/{id}" \
-H "Authorization: Bearer inboxy_your_token"
Web events
GET/api/v1/web-eventsautomations:read
List web event integrations
Requires automations:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/web-events" \
-H "Authorization: Bearer inboxy_your_token"
POST/api/v1/web-eventsautomations:write
Create an integration your website posts events to
Requires automations:write permission.
Body
namerequired
string
description
string
authTyperequired
HMAC_SHA256 | API_KEY
How your site authenticates when it posts events to POST /api/webhook/web-events/:integrationId — an `X-Webhook-Signature` HMAC-SHA256 of the raw body, or the secret in `X-Api-Key`. The secret is shown in the dashboard.
autoCreateContact
boolean
Create a contact when an event matches none.
contactMapping
object
`{ phoneField, emailField, nameField?, autoCreate, enrichFields?, displayColumns? }` — which JSON fields identify the contact.
curl -X GET "https://api.inboxy.chat/api/v1/web-events/{id}" \
-H "Authorization: Bearer inboxy_your_token"
PUT/api/v1/web-events/{id}automations:write
Update an integration
Requires automations:write permission.
Path parameters
idrequired
string
Body
namerequired
string
description
string
authTyperequired
HMAC_SHA256 | API_KEY
How your site authenticates when it posts events to POST /api/webhook/web-events/:integrationId — an `X-Webhook-Signature` HMAC-SHA256 of the raw body, or the secret in `X-Api-Key`. The secret is shown in the dashboard.
autoCreateContact
boolean
Create a contact when an event matches none.
contactMapping
object
`{ phoneField, emailField, nameField?, autoCreate, enrichFields?, displayColumns? }` — which JSON fields identify the contact.
curl -X POST "https://api.inboxy.chat/api/v1/meetings/{id}/complete" \
-H "Authorization: Bearer inboxy_your_token"
POST/api/v1/meetings/{id}/cancelmeetings:write
Mark a meeting cancelled
Requires meetings:write permission.
Path parameters
idrequired
string
curl -X POST "https://api.inboxy.chat/api/v1/meetings/{id}/cancel" \
-H "Authorization: Bearer inboxy_your_token"
Account
GET/api/v1/public/usageanalytics:read
Get plan usage
Plan, billing period and usage against each plan limit (null limit = unlimited), plus API requests in the last 24 hours. Requires analytics:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/public/usage" \
-H "Authorization: Bearer inboxy_your_token"
Calendar
GET/api/v1/public/appointmentsmeetings:read
List calendar appointments
Calendar appointments, newest first. Filter by status, contact or start time. Requires meetings:read permission.
Query parameters
limit
integer
Page size, 1-100 (default 20).
pageSize
integer
Deprecated alias of `limit`.
cursor
string
The `meta.nextCursor` of the previous page. Opaque.
page
integer
Removed in favour of `cursor`. `page=1` is accepted; any other value is refused with 400.
status
scheduled | completed | cancelled
contactId
string
startAfter
string
Starts at or after.
startBefore
string
Starts at or before.
curl -X GET "https://api.inboxy.chat/api/v1/public/appointments" \
-H "Authorization: Bearer inboxy_your_token"
Connection status of every channel (WhatsApp, Instagram, Messenger, Telegram, website chat)
Aggregate connection state for all channels (WhatsApp, Instagram, Messenger, Telegram, Widget). One request, parallel-fetched. Requires channels:read permission.
curl -X GET "https://api.inboxy.chat/api/v1/me/channels" \
-H "Authorization: Bearer inboxy_your_token"
Phone number (WhatsApp) or the channel’s recipient id. Required without `conversationId`; with one, the recipient is the conversation’s customer and this field is ignored.
scheduledForrequired
string
conversationId
string
recurrence
NONE | DAILY | WEEKLY | MONTHLY
payloadrequired
object
`{kind:"text", text}` or `{kind:"template", templateName, languageCode, bodyVariables?, components?}`. Outside the 24-hour window WhatsApp needs a template (`details.reason = window_requires_template`); a repeating message on WhatsApp, Messenger or Instagram must be a template.