Alvio campaign webhook integration
Every Alvio campaign can receive contacts through its own webhook source. The campaign screen provides the source URL and a secret token. For a Salesforce Flow integration, use the Salesforce campaign OpenAPI guide.
To receive Alvio → CRM events, see the campaign webhook subscriptions guide: setup, event catalog, signatures, tests and retries.
Create a campaign source
- Open the campaign in Alvio and enable API/webhook as a contact source.
- Copy the generated webhook URL and
x-api-keytoken. The token is shown once; store it in your integration's secret manager. - For a safe test, use a draft campaign and a test contact. A draft campaign does not send immediately. An active single-message campaign with an approved template can send as soon as a contact is received; an active sequence is processed asynchronously.
The older shared Test/Production endpoints and api-key header examples do not describe the current per-campaign source. Use the URL and key shown on the campaign screen.
Existing integrations: this change does not require a webhook already in use to change its URL, header, or key. Keep its current configuration. The new results endpoint below requires a campaign source with an x-api-key token; creating or regenerating that token may require updating clients already using the source.
Send a contact
curl -X POST '<CAMPAIGN_WEBHOOK_URL>' \
-H 'Content-Type: application/json' \
-H 'x-api-key: <CAMPAIGN_API_KEY>' \
-d '{
"phone_number": "+33612345678",
"contact_name": "Jane Doe",
"contact_email": "jane@example.com",
"crm_contact_id": "00Q000000000001",
"salesforce_campaign_id": "701000000000001",
"salesforce_campaign_member_id": "00v000000000001"
}'phone_number is the canonical required field for this integration. Use E.164 format when possible. crm_contact_id is a stable Lead or Contact identifier; Alvio uses it with the normalized phone number to identify repeat deliveries to the same campaign. The Salesforce campaign and member IDs are kept as contact metadata for reconciliation. Other JSON fields can be sent as metadata, including nested contact, campaign, custom, sales, sdr, or assignees objects.
The receiver also accepts an array of contacts or { "contacts": [...] }. For Salesforce External Services, send one object per Flow action as described by the OpenAPI schema.
Optional data and assignments
| Field | Use |
|---|---|
crm_deal_id | Opportunity or deal reference. |
lifecycle_stage | CRM stage such as lead, customer, or churned; see lifecycle tracking. |
contact | Nested identity and company details, such as name, email, company, or postal_code. |
campaign | Acquisition details such as source, utm_source, or ad_id. |
custom or custom_fields | Free-form attributes for routing and templates. |
sales or sdr | Assigned person details: nom, prenom, email, lien_calendrier, slack_id, and phone_number. |
assignees | Additional assigned people; each object can carry the same fields plus a role such as sales, sdr, or support. |
You can combine sales, sdr, and assignees. A nested contact.name or contact.email can fill the display fields when contact_name or contact_email is absent. Extra fields are stored as campaign contact metadata.
Confirm the result
The generated webhook URL is a Hookdeck source. Its HTTP response confirms that the source accepted the request; it does not prove that Alvio sent a message. To read processing and delivery state, call the Alvio result endpoint with the same campaign key:
curl 'https://www.alvio.ai/api/campaigns/<CAMPAIGN_ID>/contact-results?limit=100&offset=0' \
-H 'x-api-key: <CAMPAIGN_API_KEY>'Use next_offset until it is null. Poll from offset=0 on subsequent runs because existing contacts can change status. delivery_status describes the most recent campaign message (sent, delivered, read, replied, or failed); contact_status, sequence_status, and progress_status describe campaign execution. A null delivery status means no message record is available yet.
The OpenAPI 3.0 contract (opens in a new tab) also exposes a direct Alvio intake operation with a structured processing response. It requires a campaign with a generated API token. A successful HTTP 200 can still report nonzero errors or skipped, so inspect those counters.
Urgent appointments and callbacks
Urgency fields are available in outgoing campaign webhooks for every campaign and client. MEETING_BOOKED and ESCALATION can identify an urgent appointment or callback. Other event types include urgent: false and urgency_reason: null.
In the campaign's webhook subscriptions, subscribe your receiving endpoint to both events with event_type: "update". MEETING_BOOKED reports a confirmed appointment. ESCALATION reports a handoff to an advisor, including a callback request that has not booked a calendar slot.
Urgency fields
| Field | Type | Meaning |
|---|---|---|
data.urgent | boolean | true when the request should be prioritized; otherwise false. |
data.urgency_reason | string or null | immediate_request, within_10_minutes, or null when not urgent. |
For MEETING_BOOKED, urgent is true when the appointment starts between 0 and 10 minutes, inclusive, after the booking was recorded in Alvio. The reason is within_10_minutes. For example, a booking recorded at 09:00 for a 09:10 start is urgent; a 09:10:01 start is not. Already-past or invalid start times do not trigger urgency.
The comparison uses absolute timestamps, independently of the display timezone. It uses the original booking time, not the webhook delivery time: an appointment booked yesterday does not become urgent because its webhook arrives shortly before the call.
Example excerpt, for a booking recorded at 09:00:
{
"event_type": "update",
"event_name": "MEETING_BOOKED",
"data": {
"meeting_type": "callback",
"booking_status": "confirmed",
"start": "2026-10-12T09:10:00+02:00",
"end": "2026-10-12T09:20:00+02:00",
"timezone": "Europe/Paris",
"location": "phone",
"urgent": true,
"urgency_reason": "within_10_minutes"
}
}Immediate callback without a confirmed appointment
For ESCALATION, when the agent records a structured callback request, an explicit request to be called now, immediately, or as soon as possible produces urgent: true with urgency_reason: "immediate_request". An explicit request for a callback within the next 5 or 10 minutes produces urgent: true with urgency_reason: "within_10_minutes".
{
"event_type": "update",
"event_name": "ESCALATION",
"data": {
"status": "escalated",
"reason": "The prospect requests an immediate callback.",
"urgent": true,
"urgency_reason": "immediate_request"
}
}Without an explicit urgent callback request, later or vague callback preferences, questions, and subscription requests are not urgent: urgent: false, urgency_reason: null. A high escalation priority alone does not mean an urgent callback; read data.urgent.
An urgent callback request does not create a calendar appointment or guarantee an advisor's callback time. It goes through the existing webhook processing queue, so urgency does not guarantee immediate delivery. Appointment duration, opening hours, and timezone follow each campaign’s scheduling configuration. Urgency does not override a refusal or STOP.
Delivery and compatibility
These examples are excerpts: the existing envelope also includes event_id, occurred_at, lead, external_references, alvio, and source_data. The envelope version remains 2026-04-08.
The urgency decision is stored before delivery. Retries and redeliveries preserve the same flag and reason; deduplicate using event_id. Older events may omit both fields: treat this as urgency not provided. Existing events are not resent just to add urgency. Previously queued deliveries keep their original payload. If an older booking has no reliable original booking timestamp, or a handoff has no structured callback timing, urgency is not inferred from delivery time, free text, lead metadata, or escalation priority.
Errors and security
401: Missing or invalid campaign key. Check that the key belongs to this campaign.400or422: Invalid request, empty contact list, or a campaign-specific validation rule.404: Unknown campaign ID on the direct API.5xxor timeout: Retry with backoff. Use a stablecrm_contact_idto make repeat deliveries identifiable.
Use HTTPS, keep the API key out of logs and Flow variables visible to users, and rotate it from the campaign screen if it is exposed. A newly generated key invalidates the previous key.