Webhooks
Arbol uses Svix as its outbound webhook delivery platform. Internally, Arbol receives provider events from systems such as ElevenLabs and Kapso, normalizes them into Arbol domain models, persists the relevant state, and only then emits outbound webhook events to customer-defined endpoints through Svix. This guide documents:- How Arbol webhooks are designed
- How webhook events should be named going forward
- What the current public catalog looks like today
- How integrators should consume webhook deliveries safely
- How the Arbol team should add new events in the future
Table of Contents
- Platform Overview
- Current Public Catalog
- Event Naming Standard
- Payload Envelope
- Payload Design Rules
- Current Event Reference
- Planned Event Families
- Delivery Model
- Consumer Integration Guidelines
- How Arbol Should Add New Events
- Syncing Svix
- Versioning and Compatibility
Platform Overview
Arbol webhooks are domain events, not raw provider pass-through notifications. That distinction matters. Provider webhooks often contain provider-specific fields, partial state, or transport details that are useful internally but not ideal as the long-term public interface for customer integrations. Arbol’s webhook platform is designed to translate those raw inputs into stable business events. The intended flow is:- A provider event or product action occurs.
- Arbol validates and normalizes that input.
- Arbol persists or updates its own database records.
- Arbol emits a stable outbound event to Svix.
- Svix handles delivery, retries, signatures, endpoint fanout, replay, and observability.
Why this design exists
This model lets Arbol:- Keep provider-specific details private unless explicitly useful
- Emit payloads that match Arbol’s own data model
- Avoid sending partially processed state
- Maintain a cleaner, future-proof integration surface
- Change internal implementation details without breaking customer integrations
What this means in practice
When possible, outbound events should be emitted after Arbol has:- resolved the organization
- resolved or created the relevant conversation
- resolved the contact
- stored messages
- stored evaluations, properties, or scorecards if those belong to the event
Current Public Catalog
Arbol currently publishes exactly two public event types:call.completedwhatsapp.message.received
Important note about naming
The current V1 public catalog started before the naming standard in this document was finalized. Future events should follow the naming convention described below. That means:- existing implemented names remain the source of truth for current integrations
- future events should follow the new naming rules
- if Arbol later renames an existing event for consistency, it should be done through a compatibility plan rather than a silent breaking change
Event Naming Standard
For future event types, Arbol should use this convention:domain.resource.action
Use additional segments only when they add real meaning:
domain.resource.subresource.action
Examples:
crm.contact.createdcrm.contact.updatedcrm.contact.deletedcall.updatedcall.completedcall.evaluatedcall.scoredwhatsapp.message.sentwhatsapp.message.deliveredwhatsapp.channel.connected
Naming principles
Good event names are:- short
- predictable
- resource-oriented
- action-oriented
- free of redundant hierarchy
call.status.updatedcrm.contact.note.added.updatedwhatsapp.channel.connection.connected
call.updatedcrm.contact.updatedwhatsapp.channel.connected
Model the thing that changed
A useful rule of thumb is: If the resource that changed is the contact, emitcrm.contact.updated, even if the immediate cause was “a note was added” or “AI enrichment updated the contact”.
The reason can live in the payload:
Recommended action verbs
Prefer this vocabulary:createdupdateddeletedconnecteddisconnectedreceivedsentdeliveredreadfailedcompletedevaluatedscored
- prefer
call.completedovercall.finished_successfully - prefer
call.updatedovercall.status.updated - prefer
call.scoredovercall.scorecard.completedunless scorecards are intentionally exposed as a first-class public resource
Payload Envelope
Every outbound webhook delivery uses the same top-level envelope:Envelope fields
-
typeThe event type identifier, such ascall.completedorwhatsapp.message.received. -
timestampThe timestamp when Arbol emitted the webhook payload. -
dataThe event-specific payload.
Why the envelope matters
This shape allows consumers to:- route by event type quickly
- log or store a uniform structure
- reuse common validation logic across events
- support a single endpoint receiving many event types
Payload Design Rules
All future payloads should follow these rules.1. Use Arbol IDs wherever possible
If Arbol has already persisted a record, payloads should prioritize Arbol identifiers:org_*cnt_*cnv_*agt_*msg_*
2. Include stable business context
When relevant, payloads should include:organizationconversationagentcontactchannelmessage
3. Avoid provider-only payloads
Provider-specific metadata is useful, but it should not dominate the public contract. If it is included, place it in a clearly scoped field such as:providerexternalmetadata
4. Prefer resource snapshots over partial fragments
For most public events, it is better to send a coherent snapshot of the relevant object than a tiny patch with no surrounding context. For example,whatsapp.message.received should include the normalized message plus conversation, contact, and channel context instead of only a raw message ID and text body.
5. Use updated plus payload detail instead of event-name explosion
If the same resource can change for many reasons, keep the event name broad and express the cause in payload fields.
For example:
- event name:
crm.contact.updated - payload detail:
changes,updatedFields,source,reason
6. Emit only after meaningful state is ready
If an event claims that a process is complete, the payload should reflect the finalized state. Examples:call.completedshould only fire after post-call processing is finishedcall.scoredshould only fire after scorecard generation is donewhatsapp.message.receivedshould only fire after the inbound message has been normalized and stored
Current Event Reference
call.completed
Sent when a voice call reaches a terminal state after Arbol finishes post-call processing.
Included data:
- organization identifiers
- conversation metadata and terminal status
- agent and contact context
- transcript messages
- extracted properties
- evaluation results
whatsapp.message.received
Sent when Arbol receives, normalizes, and stores an inbound customer WhatsApp message.
Included data:
- organization identifiers
- WhatsApp channel metadata
- conversation context
- agent and contact context
- normalized message content and message metadata
Planned Event Families
The following families are good candidates for future additions. These names are recommendations, not currently implemented public events.CRM events
crm.contact.createdcrm.contact.updatedcrm.contact.deleted
- manual editing
- AI enrichment
- note creation
- contact point verification
changesupdatedFieldssourcereason
Call events
call.updatedcall.completedcall.evaluatedcall.scored
- Use
call.updatedfor meaningful state changes - Use
call.completedfor finalized post-call state - Use
call.evaluatedwhen evaluation criteria have been persisted - Use
call.scoredwhen the scorecard has been computed and stored
WhatsApp message events
whatsapp.message.receivedwhatsapp.message.sentwhatsapp.message.deliveredwhatsapp.message.readwhatsapp.message.failed
WhatsApp channel events
whatsapp.channel.connectedwhatsapp.channel.disconnected
WhatsApp conversation events
whatsapp.conversation.createdwhatsapp.conversation.inactivewhatsapp.conversation.endedwhatsapp.conversation.completed
whatsapp.conversation.completed when you want to expose the point at which Arbol has already processed the conversation and the final normalized state is ready for external systems.
Delivery Model
Arbol webhook delivery should be treated as at-least-once. Consumers must assume:- the same event may be delivered more than once
- delivery order is not guaranteed across different events
- there may be retries after transient failures
Event identity
When available, Arbol should provide a stable event identifier through Svix’seventId.
Recommended patterns:
- for call completion events, use the Arbol conversation ID
- for inbound WhatsApp message events, use the upstream WhatsApp message ID if available, otherwise the stored Arbol message ID
- for future update events, use a deterministic ID that reflects the actual state transition or mutation
Fast acknowledgment
Consumers should return a2xx response quickly and do longer processing asynchronously.
Replay support
Svix replay is part of the operational contract. Consumers should make their handlers idempotent so replaying a message is safe.Consumer Integration Guidelines
If you are consuming Arbol webhooks, your endpoint should:- accept
POSTrequests - verify Svix signatures before processing
- treat deliveries as at-least-once
- use
typefor routing - store processed event IDs for idempotency
- enqueue long-running work instead of blocking the webhook response
Recommended handler flow
- Receive the request.
- Verify the Svix signature.
- Parse the JSON envelope.
- Check whether the event has already been processed.
- Route by
type. - Persist or enqueue downstream work.
- Return
2xx.
Idempotency strategy
Store one of the following:- Svix message ID
- webhook
eventId - a derived stable processing key
How Arbol Should Add New Events
Every new public event should follow the same lifecycle.1. Define the event in the shared catalog
Each catalog entry should include:- event type
- display name
- short description
- JSON Schema
- example payload
- logical group name
2. Decide the correct emission point
Emit the event from the place where Arbol has the right level of truth. Usually that means:- after persistence
- after normalization
- after enrichment
- after evaluation or scoring if those are part of the meaning of the event
3. Build the payload from Arbol’s domain context
Payloads should prefer:- database-backed identifiers
- normalized conversation state
- normalized contact data
- channel metadata from Arbol records
4. Document the event
Every public event should be described in this guide and exposed through the Svix Event Catalog.5. Sync Svix
After catalog changes, sync them to Svix so the App Portal stays aligned with the code.Syncing Svix
Arbol keeps the Svix event catalog in code. When the catalog changes, sync it to Svix with:- event types
- descriptions
- logical group names
- JSON Schemas
- example payloads
Versioning and Compatibility
Webhook contracts should be treated as public APIs.Safe changes
These are generally safe:- adding optional fields
- adding new event types
- improving descriptions and examples
- adding non-breaking metadata fields
Breaking changes
These require a compatibility plan:- renaming an event type
- removing existing fields
- changing field semantics
- changing ID strategy unexpectedly
Recommended approach to breaking changes
Prefer one of these:- publish a new event name
- support both old and new names temporarily
- document the migration window clearly
Summary
Arbol’s webhook platform should be built around stable domain events rather than raw provider callbacks. The most important long-term rules are:- keep the public catalog small and intentional
- use clear event names such as
crm.contact.updatedorwhatsapp.message.delivered - prefer normalized Arbol state over raw provider payloads
- emit events only after meaningful state is ready
- document every public event in code and in Svix