Webhooks
Introduction
Section titled “Introduction”Webhooks let Aelyst communicate with your external systems in real time. When an event occurs in your workspace — a new contact is created, a message is received, a conversation is closed — Aelyst sends an HTTP POST request to a URL you configure, known as a webhook endpoint. That endpoint can point to any third-party service or your own backend, letting you automate actions in response to events without polling the API.
For example, when a new contact is created, a webhook can automatically add that contact to a mailing list in a connected email service. Webhooks give you a flexible, efficient way to integrate Aelyst with the rest of your stack.
Configuration
Section titled “Configuration”Webhooks are configured under Settings > Integrations > Webhooks.
Each workspace can create up to 35 webhook endpoints.
Events
Section titled “Events”| Event | Description |
|---|---|
| Contact Tag Updated | Triggers when tag(s) are removed or added on a contact. |
| New Contact | Triggers when a new contact is created. |
| Contact Updated | Triggers when any contact fields of a contact are updated. |
| Conversation Opened | Triggers when a conversation is opened. |
| Conversation Closed | Triggers when a conversation is closed. |
| New Comment | Triggers when a new comment is posted to a conversation. |
| New Outgoing Message | Triggers when a message is sent. |
| New Incoming Message | Triggers when a message is received. |
| Contact Assignee Updated | Triggers when the assignee of a contact is updated. |
| Lifecycle Updated | Triggers when contact lifecycle is updated. |
| Call Ended | Triggers when a call ends. |
Verifying the Payload
Section titled “Verifying the Payload”A webhook signature lets you verify that an incoming request genuinely came from Aelyst.
Aelyst adds an X-Webhook-Signature header to every webhook request. Verify authenticity by recomputing the signature and comparing. It’s built with the HMAC-SHA256 algorithm using the signing key (signingKey) shown during configuration, applied to the JSON-stringified request body, then encoded as base64.
Example
Section titled “Example”Verifying the webhook signature in Node.js:
const express = require('express');const bodyParser = require('body-parser');const { createHmac } = require('crypto');const app = express();
app.use(express.json());app.use(bodyParser.urlencoded({ extended: true }));
app.post('/', (req, res) => { const signature = req.get('X-Webhook-Signature'); const signingKey = 'my-signing-key';
const expectedSignature = createHmac('sha256', signingKey) .update(JSON.stringify(req.body)) .digest('base64');
if (signature !== expectedSignature) { return res.status(400).json({ message: 'Invalid signature' }); }
res.json({ message: 'ok' });});
app.listen(3000, () => console.log('Listening on port 3000'));Error Handling
Section titled “Error Handling”If your endpoint doesn’t return a 200 response, Aelyst treats it as an error. If errors exceed 30 within 30 minutes, the webhook endpoint is deactivated.
Retry Mechanism
Section titled “Retry Mechanism”If a webhook request doesn’t return a 200 within 5 seconds, Aelyst retries. Three retries are attempted at intervals of 30s, 60s, and 90s until a 200 is received.
Event Payloads
Section titled “Event Payloads”Each event delivers a JSON payload. Below is the example payload for each event type.
Contact Tag Updated
Section titled “Contact Tag Updated”Triggers when tag(s) are removed or added on a contact.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "tags": [ "sampleTag1", "sampleTag2" ], "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "tag": "sampleTag2", "action": "add", "event_type": "contact.tag.updated", "event_id": "51f4244b-266d-49d9-9477-74dfeea7dae4"}New Contact
Section titled “New Contact”Triggers when a new contact is created.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "tags": [ "sampleTag1", "sampleTag2" ], "blood_group": null, "employee_type": null, "bool": null, "number": null, "phone_number_02": null, "new_1_text": null, "new_2_text": null, "new_2": null, "test_field": null, "test": null, "rgwgrwrwg": null, "alfqrat_fy_alsfgrw": null, "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "event_type": "contact.created", "event_id": "a96bbd0e-7463-4bdc-a49e-24ca9f183bfb"}Contact Updated
Section titled “Contact Updated”Triggers when any contact fields of a contact are updated.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "tags": [ "sampleTag1", "sampleTag2" ], "blood_group": null, "employee_type": null, "bool": null, "number": null, "phone_number_02": null, "new_1_text": null, "new_2_text": null, "new_2": null, "test_field": null, "test": null, "rgwgrwrwg": null, "alfqrat_fy_alsfgrw": null, "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "event_type": "contact.updated", "event_id": "5733378c-ec01-4bef-87a0-023edcda63f2"}Conversation Opened
Section titled “Conversation Opened”Triggers when a conversation is opened.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "conversation": { "source": "api", "conversationOpenedAt": 1663274081, "firstIncomingMessage": "hello", "firstIncomingMessageChannelId": 1 }, "event_type": "conversation.opened", "event_id": "8b9c2905-7a38-4aad-a6b7-b9120dc140fe"}Conversation Closed
Section titled “Conversation Closed”Triggers when a conversation is closed.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "conversation": { "category": "sampleCategory", "summary": "sample summary", "openedTime": 1663274081, "openedBySource": "user", "closedTime": 1663274081, "closedBy": { "id": null, "firstName": null, "lastName": null, "email": null }, "closedBySource": "api", "firstResponseTime": 1663274081, "resolutionTime": 1663274081, "incomingMessageCount": 10, "outgoingMessageCount": 5, "assigneeTeam": "My team", "lastAssignmentTime": 1663274081 }, "event_type": "conversation.closed", "event_id": "563eddae-a807-48b8-9a8a-f02dc3bc25cc"}New Comment
Section titled “New Comment”Triggers when a new comment is posted to a conversation.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "text": "Sample comment", "mentionedUserIds": [ 1, 2 ], "mentionedUserEmails": [ "test@example.com", "test1@example.com" ], "event_type": "comment.created", "event_id": "880dca69-2076-4d32-938b-d42d24a6af5c"}New Outgoing Message
Section titled “New Outgoing Message”Triggers when a message is sent.
We offer the choice to select the message type to be sent to your endpoint, and the payload of the webhook is dependent on the chosen message type. You can find the sample payload for each message type by clicking on the dropdown of examples.
Default: Text Message
Example 1: Attachment Message
Example 2: Custom Payload Message
Example 3: Email
Example 4: Product Message
Example 5: Quick Reply
Example 6: WhatsApp Template
Example 7: Card
{ "event_type": "message.sent", "event_id": "3bf5734f-4036-412b-a4de-cf72895492f2", "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "email": "johndoe@sample.com", "firstName": "John", "lastName": "Doe" }, "created_at": 1663274081 }, "message": { "messageId": 1262965213, "channelMessageId": 123, "contactId": 123, "channelId": 123, "traffic": "outgoing", "timestamp": 1662965213, "message": { "type": "text", "text": "Message text" }, "status": [ { "value": "pending", "timestamp": 1662965213 }, { "value": "failed", "timestamp": 1662965213, "message": "Failed reason" } ] }, "channel": { "id": 1, "name": "string", "source": "facebook", "meta": "{}", "created_at": 1663274081, "lastMessageTime": 1663274123, "lastIncomingMessageTime": 1663274134 }, "user": { "id": 2, "email": "johndoe@sample.com", "firstName": "John", "lastName": "Doe" }, "sender": { "source": "user", "userId": 123456789, "teamId": 123456789, "workflowId": 123456789, "broadcastHistoryId": null }, "source": "User"}New Incoming Message
Section titled “New Incoming Message”Triggers when a message is received.
We offer the choice to select the message type to be sent to your endpoint, and the payload of the webhook is dependent on the chosen message type. You can find the sample payload for each message type by clicking on the dropdown of examples.
Default: Text Message
Example 1: Attachment Message
Example 2: Email
Example 3: Location
Example 4: Product Message
Example 5: Sticker Message
Example 6: Story Reply
Example 7: Unsupported Message
{ "event_type": "message.received", "event_id": "2bfe3c89-a074-4188-98cf-909c5b07eff3", "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "email": "johndoe@sample.com", "firstName": "John", "lastName": "Doe" }, "created_at": 1717558775 }, "message": { "messageId": 1726740558441000, "channelMessageId": 123, "contactId": 123, "channelId": 123, "traffic": "incoming", "timestamp": 1726740558441, "message": { "type": "text", "text": "Message text", "messageTaG": "ACCOUNT_UPDATE" }, "replyTo": { "id": 1763973918123456, "mId": "8402123456_58159021_9", "message": { "type": "text", "text": "Hi, how can I help?" }, "sender": { "source": "user", "type": "message", "userId": 123, "teamId": 123 } } }, "sender": { "source": "contact", "userId": 123456789, "teamId": 123456789, "workflowId": 123456789, "broadcastHistoryId": 123456789 }, "channel": { "id": 1, "name": "string", "source": "facebook", "meta": "{}", "created_at": 1701403960 }}Contact Assignee Updated
Section titled “Contact Assignee Updated”Triggers when the assignee of a contact is updated.
{ "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "created_at": 1663274081 }, "event_type": "contact.assignee.updated", "event_id": "12f2b584-6f84-407d-8b5f-19035d2b06e7"}Lifecycle Updated
Section titled “Lifecycle Updated”Triggers when contact lifecycle is updated.
{ "event_type": "contact.lifecycle.updated", "event_id": "12f2b584-6f84-407d-8b5f-19035d2b06e7", "contact": { "id": 1, "firstName": "John", "lastName": "Doe", "phone": "+60123456789", "email": "johndoe@sample.com", "language": "en", "profilePic": "https://cdn.cdn.aelyst.ai/johndoe.png", "countryCode": "MY", "status": "open", "assignee": { "id": 2, "firstName": "John", "lastName": "Doe", "email": "johndoe@sample.com" }, "tags": [ "sampleTag1", "sampleTag2" ], "lifecycle": "New Lead", "created_at": 1663274081 }, "lifecycle": "New Lead", "oldLifecycle": "Hot Lead", "action": "updated"}Call Ended
Section titled “Call Ended”Triggers when a call ends.
The Call Ended webhook is triggered whenever a voice call session terminates, whether the call was completed or uncompleted. The payload includes core call metadata (call ID, direction, status, timestamps, and duration for completed calls), along with the associated contact, the final handling user (agent or AI), and the channel information.
For completed calls (status: “completed”), enrichment fields depend on feature configuration. If recording, transcription, and summarization are enabled, the payload includes recordingURL, language, a structured transcript, and a callSummary. If only recording is enabled, recordingURL is populated while language, transcript, and callSummary are null. If recording is disabled, all enrichment fields (recordingURL, language, transcript, callSummary) are null.
For uncompleted calls (status: “uncompleted”), no recording or AI enrichment data is included. Only basic call, contact, user, and channel metadata are returned.
The user object always represents the last handler of the call. If handled by a human agent, the role reflects their Workspace role; if handled by Voice AI, the role is ai_agent. In transferred calls, only the final handling user is recorded.
{ "call": { "id": "abcde", "direction": "inbound", "channel": "WhatsApp", "language": "en", "status": "completed", "durationSeconds": 37, "end_time": "1764216241", "start_time": "1764216235", "recordingURL": "https://cdn.aelyst.ai/call/recording/123/abcd1234.mp3", "transcript": [ { "start": 0.079, "end": 27.919, "text": "Hello, ths is John from Smash and Serve, how may I help you?", "speaker": "John" }, { "start": 0.459, "end": 8.019, "text": "Hello, my name is Charles, may I know what is the available color for the Victory racket?", "speaker": "Charles" }, { "start": 8.019, "end": 13.739, "text": "Hello Charles, please give me a moment to check on the available colors.", "speaker": "John" }, { "start": 13.739, "end": 19.76, "text": "Right now the available colors are Crimson Red, Royal Blue, and Oak Green.", "speaker": "John" }, { "start": 19.76, "end": 22.78, "text": "Nice, what time do you guys close today?", "speaker": "Charles" }, { "start": 22.78, "end": 25.6, "text": "We will be opened until 9pm tonight", "speaker": "John" }, { "start": 25.6, "end": 28.619, "text": "Nice, can you reserve a Crimson Red one for me? I can pick it up later around 8.", "speaker": "Charles" }, { "start": 28.619, "end": 30.919, "text": "Sure, can I get your full name and number sir?", "speaker": "John" }, { "start": 30.919, "end": 33.719, "text": "Okay, my full name is Charles Hamilton and my number is 0118889988.", "speaker": "Charles" }, { "start": 33.719, "end": 35.623, "text": "Thank you sir, we have reserved the racket for you, see you later.", "speaker": "John" }, { "start": 35.623, "end": 36.901, "text": "Thank you, see you later", "speaker": "Charles" } ], "callSummary": { "title": "Customer Inquiry and Reservation for Victory Racket", "summary": [ "Charles contacted Smash and Serve to inquire about the available colors for the Victory racket.", "John confirmed the available colors as Crimson Red, Royal Blue, and Oak Green.", "Charles asked about store closing time and was informed it closes at 9 pm.", "Charles requested to reserve a Crimson Red racket for pickup around 8 pm.", "John took Charles’s details and confirmed the reservation." ], "actionItems": [ "John at Smash and Serve will hold the Crimson Red Victory racket reserved for Charles Hamilton.", "Charles Hamilton will pick up the reserved racket around 8 pm today." ] } }, "contact": { "id": "87654321", "firstName": "Charles", "lastName": "Hamilton", "phone": "+60123456789" }, "user": { "id": "12345678", "firstName": "John", "lastName": "Doe", "email": "john.doe@aelyst.ai", "role": "owner" }}