Webhooks
One signed endpoint that receives events for every client org you manage
Webhooks are how a machine gets realtime: an API key cannot open a GraphQL subscription, so live updates always arrive as signed HTTP posts.
Webhooks need a Pro or Enterprise plan for a retail organisation. Tech providers and their client organisations are unaffected - the fan-out webhook described here is part of the provider model, not a retail plan feature.
Manage the subscription with the webhook subscription operations - dashboard login only.
One Concept, Two Delivery Scopes
It is the same event catalogue, the same envelope, the same HMAC signing and the same retry policy either way. Only who receives what differs.
| A normal org | A tech provider | |
|---|---|---|
| Registers | Its own outbound webhook | One fan-out webhook |
| Receives events from | That one org | Every managed client org |
| Routing needed | None - single org | By meta.organisationId or meta.externalId |
meta.partnerId / externalId | Absent | Present |
meta.connectionId | Present | Absent |
A tech provider registers once and never again as clients come and go - a new client org starts delivering to the same endpoint automatically.
Where Each Is Configured
| Set up via | |
|---|---|
| Partner fan-out webhook | registerPartnerWebhook, by a member of the provider org |
| Per-org webhook | Settings → Webhooks and API → Webhooks in the dashboard - see the operator guide at Webhooks & API |
The operator guide also covers inbound webhooks (an external system posting into Wexio to trigger a flow), which have nothing to do with the events below. The rest of this section describes the partner fan-out shape; a per-org webhook carries the same events with connectionId in place of partnerId/externalId.
Routing an Event
Each delivery carries two identifiers for the client it came from:
"meta": {
"organisationId": "6716b2f0a1c34d0012ab89ef",
"externalId": "crmco-client-5541",
"partnerId": "6716b1001c34d0012ab89abc"
}organisationId- the Wexio client org.externalId- your ID for that client, as passed tocreateClientOrg. Set it at provisioning time and you never need a mapping table.partnerId- your own provider org. Constant across every delivery.
Event Catalogue
type on the wire uses the dotted lowercase form. The events argument of the subscription mutations uses the GraphQL enum name.
Wire name (type) | Enum name (subscribe with this) | Page |
|---|---|---|
message.inbound.created | MESSAGE_INBOUND_CREATED | Messages |
message.inbound.updated | MESSAGE_INBOUND_UPDATED | Messages |
message.inbound.deleted | MESSAGE_INBOUND_DELETED | Messages |
message.outbound.created | MESSAGE_OUTBOUND_CREATED | Messages |
message.outbound.updated | MESSAGE_OUTBOUND_UPDATED | Messages - edits only |
message.outbound.status | MESSAGE_OUTBOUND_STATUS | Delivery status - opt-in |
message.outbound.deleted | MESSAGE_OUTBOUND_DELETED | Messages |
chat.created | CHAT_CREATED | Chats |
chat.updated | CHAT_UPDATED | Chats |
chat.deleted | CHAT_DELETED | Chats |
conversation.created | CONVERSATION_CREATED | Conversations |
conversation.updated | CONVERSATION_UPDATED | Conversations |
contact.created | CONTACT_CREATED | Contacts |
contact.updated | CONTACT_UPDATED | Contacts |
contact.deleted | CONTACT_DELETED | Contacts |
contact.merged | CONTACT_MERGED | Contacts |
contact.split | CONTACT_SPLIT | Contacts |
comment.created | COMMENT_CREATED | Comments & posts |
comment.updated | COMMENT_UPDATED | Comments & posts |
comment.deleted | COMMENT_DELETED | Comments & posts |
post.created | POST_CREATED | Comments & posts |
post.deleted | POST_DELETED | Comments & posts |
organisation.deleted | ORGANISATION_DELETED | Organisation |
The flow Namespace
The catalogue also reserves FLOW, a namespace for events a flow author emits by hand from an Outbound Webhook Event card (flow.order_confirmed, flow.lead_qualified, …).
flow.* is not useful for an API-key integration. Flows are built in the dashboard, and flow authoring is not part of the API - so a headless client org that never builds a flow never emits a flow.* event. It is documented as an org-level extensibility hook in the operator guide: flow.<suffix> - Custom Flow Events.
For a partner integration, the meaningful events are the system ones above: they fire automatically, with no setup inside the client org.
Minimum Viable Subscription
If you only want to mirror conversations into your own product, subscribe to these four:
mutation Register {
registerPartnerWebhook(
url: "https://api.crmco.com/wexio/webhook"
events: [
MESSAGE_INBOUND_CREATED
MESSAGE_OUTBOUND_CREATED
CONTACT_MERGED
ORGANISATION_DELETED
]
) { id signingSecret }
}If you send messages, add MESSAGE_OUTBOUND_STATUS as well - it is the only way to learn whether a message was delivered, and the only way to complete an async send.
CONTACT_MERGED matters more than it looks: without it, two contacts you mirrored separately can silently become one on Wexio's side and your copy drifts. ORGANISATION_DELETED tells you a client is gone.
Next
- Envelope & delivery - headers, signature verification, retries, deduplication.
- Shared types - the
datapayload shapes every event reuses.