Overview
Axis Inbox is one HTTP API for connections, conversations and campaigns across WhatsApp, Meta (Facebook/Instagram), SMS, email, LiveChat and the social networks. Your app talks to Inbox; behind it sit vendor integrations you never name in code.
It is shared infrastructure, not a product surface. Several Axis apps call the same service, each scoped to its own tenants.
The mental model
A connection is one connected account — a WhatsApp number, a Facebook page, an email domain, the LiveChat widget. Inbound messages from that account arrive as provider webhooks, are verified, then normalised and ingested into a thread (a conversation) made of entries (individual messages or comments). You list threads, read one, and reply through the same connection. Everything is scoped to a tenant — a workspace — identified by a single request header. On top of that core sit tickets, contacts, labels, segments, templates, campaigns, flows and publishing, all built on the same threads and the same contact book.
What Inbox owns, and what it does not
| Concern | Owner |
|---|---|
| Connections, bindings, encrypted provider credentials | Inbox |
| Threads, entries, participants | Inbox |
| Tickets, labels, notes, canned replies | Inbox |
| Contacts, identifiers, consent, segments | Inbox |
| Templates, campaigns, flows, warm-up | Inbox |
| Posts and publishing dispatch | Inbox |
| Inbound and outbound webhooks | Inbox |
| Users and sessions | Axis Accounts |
| User groups (workspaces) | Axis Accounts |
| Apps | Axis Accounts (Inbox keeps a mirror row for local config) |
Inbox stores no users. Every *UserId column in the schema — ownerUserId, sentByUserId,
actorUserId, assignedUserId — holds an Accounts user id, never a foreign key to a local table. That
is deliberate: identity has exactly one home, and Inbox never has to keep a copy in sync.
The two things to get right
Almost every integration problem is one of these two.
The credential. Inbox authenticates against Axis Accounts. You present either an Accounts service
key (sk_…, a machine credential acting as the whole tenant) or an Accounts user session id (which
carries the operator's identity, so ownership and assignment attribute to a real person). The key must
carry inbox:* scopes, and those scopes must have been published to Accounts first — see
Connect an app.
The tenant. Every tenant-scoped call sends X-Axis-Tenant: ws_<accountsUserGroupId>. A wrong value
does not error. It silently provisions a fresh, empty workspace, and your data appears to have vanished.
This is the single most common integration failure, and Tenancy exists mostly
to explain it.
A note on the name
This service is Axis Inbox. It was historically called Axis Social, and you will still find that name in older code, package metadata and comments.
It is not the axis-social app registered in Axis Accounts. axis-social is one consuming app,
alongside axis-engage, axis-workspace and axis-dashboard. Inbox is the infrastructure all of them
call. The naming overlap has caused real, repeated confusion — including data migrated into the wrong
app — so it is worth reading twice: an app slug in Accounts identifies a caller, never this service.
Where to go next
| You want to | Read |
|---|---|
| Get the service running on your machine | Run it locally |
| Onboard a new consuming app | Connect an app |
| Send and receive your first message | Your first conversation |
| Understand the request pipeline and stack | Architecture |
| Understand workspace scoping | Tenancy |
| Find a model or a constraint | Data model |
| Look up a word | Glossary |