The Webhooks API allows you to receive real-time notifications about events in your TidySupport workspace. You can subscribe to conversation, message, contact, and signal events and process them in your own systems.
Webhooks send HTTP POST requests to your specified URL whenever an event happens.
You can also inspect delivery analytics for each webhook with a 7-day Tinybird-backed delivery summary.
Webhooks can be configured to listen for the following events:
CONVERSATION_CREATED - A new conversation was createdCONVERSATION_UPDATED - A conversation was updatedCONVERSATION_ASSIGNED - A conversation was assignedCONVERSATION_CLOSED - A conversation was closedCONVERSATION_REOPENED - A conversation was reopenedMESSAGE_CREATED and MESSAGE_UPDATED - Message activity inside a conversationCONTACT_CREATED - A new contact was createdSIGNAL_CREATED and SIGNAL_UPDATED - AI support signals were created or updatedTESTING_CONNECTION is reserved for endpoint verification and health checks. TidySupport sends it when testing or validating a webhook endpoint.
Lists all webhooks for the authenticated workspace.
Authentication
Requires a valid API key with api_user scope.
Request
curl "https://api.tidysupport.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"webhooks": {
"items": [
{
"id": "wh_123456789",
"url": "https://example.com/webhooks/app",
"displayName": "example.com",
"status": "ACTIVE",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"createdAt": "2023-03-01T10:00:00Z",
"updatedAt": "2023-03-01T10:00:00Z",
"lastAttemptedAt": null,
"lastErrorAt": null,
"lastErrorMessage": null
},
{
"id": "wh_987654321",
"url": "https://example.com/webhooks/signals",
"displayName": "example.com",
"status": "PAUSED",
"events": ["SIGNAL_CREATED", "SIGNAL_UPDATED"],
"createdAt": "2023-04-10T14:30:00Z",
"updatedAt": "2023-04-10T14:30:00Z",
"lastAttemptedAt": "2023-04-11T09:15:00Z",
"lastErrorAt": "2023-04-11T09:15:00Z",
"lastErrorMessage": "{"message":"connect ETIMEDOUT"}"
}
],
"hasMore": false,
"startAt": null
}
}Retrieves details of a specific webhook.
Authentication
Requires a valid API key with api_user scope.
Request
curl "https://api.tidysupport.com/v1/webhooks/wh_123456789" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"webhook": {
"id": "wh_123456789",
"url": "https://example.com/webhooks/app",
"displayName": "example.com",
"status": "ACTIVE",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"token": "wht_a1b2c3d4e5f6g7h8i9j0",
"createdAt": "2023-03-01T10:00:00Z",
"updatedAt": "2023-03-01T10:00:00Z",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"lastAttemptedAt": null,
"lastErrorAt": null,
"lastErrorMessage": null
}
}Creates a new webhook.
Authentication
Requires a valid API key with api_user scope.
Request Body
{
"url": "https://example.com/webhooks/app",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"token": "optional_secret_token"
}Request
curl -X POST "https://api.tidysupport.com/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/app",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"token": "optional_secret_token"
}'Response
{
"webhook": {
"id": "wh_123456789",
"url": "https://example.com/webhooks/app",
"displayName": "example.com",
"status": "ACTIVE",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"token": "wht_a1b2c3d4e5f6g7h8i9j0",
"createdAt": "2023-04-16T15:45:00Z",
"updatedAt": "2023-04-16T15:45:00Z",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"lastAttemptedAt": null,
"lastErrorAt": null,
"lastErrorMessage": null
}
}Updates a webhook.
Authentication
Requires a valid API key with api_user scope.
Request Body
{
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED", "SIGNAL_CREATED"]
}Request
curl -X POST "https://api.tidysupport.com/v1/webhooks/wh_123456789" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED", "SIGNAL_CREATED"]
}'Response
{
"webhook": {
"id": "wh_123456789",
"url": "https://example.com/webhooks/app",
"displayName": "example.com",
"status": "ACTIVE",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED", "SIGNAL_CREATED"],
"token": "wht_a1b2c3d4e5f6g7h8i9j0",
"createdAt": "2023-03-01T10:00:00Z",
"updatedAt": "2023-03-02T12:15:00Z",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"lastAttemptedAt": null,
"lastErrorAt": null,
"lastErrorMessage": null
}
}Deletes a webhook.
Authentication
Requires a valid API key with api_user scope.
Request
curl -X DELETE "https://api.tidysupport.com/v1/webhooks/wh_123456789" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"webhook": {
"id": "wh_123456789",
"url": "https://example.com/webhooks/app",
"displayName": "example.com",
"status": "ACTIVE",
"events": ["CONVERSATION_CREATED", "MESSAGE_CREATED"],
"token": "wht_a1b2c3d4e5f6g7h8i9j0",
"createdAt": "2023-03-01T10:00:00Z",
"updatedAt": "2023-03-02T12:15:00Z",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"lastAttemptedAt": "2023-03-05T11:30:00Z",
"lastErrorAt": null,
"lastErrorMessage": null
},
"isDeleted": true
}Returns Tinybird-backed delivery totals plus a day-by-day timeseries for the last 7 days.
Authentication
Requires a valid API key with api_user scope.
Request
curl "https://api.tidysupport.com/v1/webhooks/wh_123456789/delivery-analytics" \
-H "Authorization: Bearer YOUR_API_KEY"Response
{
"timeseries": [
{
"day": "2023-04-10",
"successes": 12,
"failures": 1
},
{
"day": "2023-04-11",
"successes": 8,
"failures": 0
},
{
"day": "2023-04-12",
"successes": 15,
"failures": 2
}
],
"stats": {
"totalSuccesses": 35,
"totalFailures": 3,
"totalAttempts": 38,
"lastAttemptedAt": "2023-04-12T18:15:00Z",
"lastErrorAt": "2023-04-12T18:12:00Z"
}
}When an event occurs, TidySupport will send a POST request to your webhook URL with a JSON payload containing an event name, payload object, version, and timestamp.
Example payload for MESSAGE_CREATED:
{
"event": "MESSAGE_CREATED",
"version": 1,
"timestamp": "2023-04-16T15:45:00.000Z",
"payload": {
"message": {
"id": "msg_h1s2JkLmNoPqRsTuVwXyZaBc",
"conversationId": "cnv_q1w2e3r4t5y6u7i8o9p0as",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"direction": "INBOUND",
"senderType": "CONTACT",
"contentText": "I need help with my billing plan.",
"contentPreview": "I need help with my billing plan.",
"createdAt": "2023-04-16T15:45:00.000Z"
},
"conversation": {
"id": "cnv_q1w2e3r4t5y6u7i8o9p0as",
"workspaceId": "wrk_ENGTK86JEXXckyDVJthKkPer",
"status": "OPEN",
"subject": "Billing question",
"source": "WIDGET",
"lastMessageAt": "2023-04-16T15:45:00.000Z",
"lastMessagePreview": "I need help with my billing plan.",
"createdAt": "2023-04-16T15:44:30.000Z"
}
}
}Example payload for TESTING_CONNECTION:
{
"event": "TESTING_CONNECTION",
"version": 1,
"timestamp": "2023-04-16T16:30:00.000Z",
"payload": {
"message": "Testing your webhook endpoint. Respond with a 200 status code."
}
}TidySupport includes the following headers on each webhook request:
x-tidysupport-webhook-token - The webhook token you configured. Use it to authenticate the request.x-tidysupport-dedup-key - A unique delivery ID you can store for idempotency and deduplication.Example in Node.js:
const express = require('express');
const app = express();
app.use(express.json());
const WEBHOOK_TOKEN = 'YOUR_WEBHOOK_TOKEN';
app.post('/webhooks/app', (req, res) => {
const token = req.headers['x-tidysupport-webhook-token'];
const dedupKey = req.headers['x-tidysupport-dedup-key'];
if (token !== WEBHOOK_TOKEN) {
return res.status(401).send('Unauthorized');
}
console.log('Webhook verified:', req.body.event, dedupKey);
switch (req.body.event) {
case 'CONTACT_CREATED':
console.log(req.body.payload.contact.id);
break;
case 'CONVERSATION_CREATED':
console.log(req.body.payload.conversation.id);
break;
case 'MESSAGE_CREATED':
console.log(req.body.payload.message.id);
break;
default:
console.log('Unhandled event type:', req.body.event);
}
}
return res.status(200).send('Webhook received');
});