Skip to content
  • Auto
  • Light
  • Dark
Get Started
Getting Started
View as Markdown
Copy Markdown

Open in Claude
Open in ChatGPT

Webhooks

Webhooks allow you to receive real-time notifications when events occur in your SendBlue account. You can configure multiple webhooks for different event types and manage them via our API.

In this documentation, we will cover how to:

  1. Understand webhook types and formats
  2. Set up and manage webhooks
  3. Secure your webhook endpoints
  4. Handle webhook events

The following webhook types are supported:

TypeDescription
receiveTriggered when you receive an inbound message
outboundTriggered when an outbound message is sent
call_logTriggered when a call log is received
line_blockedTriggered when a line is blocked
line_assignedTriggered when a line is assigned
contact_createdTriggered when a contact is created

Webhooks can be specified in two formats:

  • Simple URL string: "https://example.com/webhook"
  • Object with URL and secret: { "url": "https://example.com/webhook", "secret": "my-secret" }

You can manage your webhooks using the following API endpoints:

Retrieve all webhooks configured for your account:

Terminal window
curl -X GET https://api.sendblue.co/api/v2/account/webhooks \
-H "sb-api-key-id: YOUR_API_KEY" \
-H "sb-api-secret-key: YOUR_API_SECRET"

Response:

{
"status": "OK",
"webhooks": {
"receive": [
"https://example.com/webhook1",
{
"url": "https://example.com/webhook2",
"secret": "webhook-secret"
}
],
"call_log": [],
"line_blocked": [],
"line_assigned": [],
"outbound": [],
"contact_created": ["https://example.com/contact-webhook"],
"globalSecret": "global-secret"
}
}

Add new webhooks to your account. This endpoint appends to the existing webhook list:

Terminal window
curl -X POST https://api.sendblue.co/api/v2/account/webhooks \
-H "sb-api-key-id: YOUR_API_KEY" \
-H "sb-api-secret-key: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"webhooks": [
"https://example.com/new-webhook",
{
"url": "https://example.com/webhook-with-secret",
"secret": "my-webhook-secret"
}
],
"type": "receive"
}'

Parameters:

ParameterTypeRequiredDescription
webhooksarrayYesArray of webhook URLs or webhook objects
typestringNoWebhook type (default: receive)
globalSecretstringNoGlobal secret to apply to all webhooks

Replace the entire webhook configuration for your account:

Terminal window
curl -X PUT https://api.sendblue.co/api/v2/account/webhooks \
-H "sb-api-key-id: YOUR_API_KEY" \
-H "sb-api-secret-key: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"webhooks": {
"receive": ["https://example.com/webhook"],
"call_log": ["https://example.com/call-webhook"],
"contact_created": ["https://example.com/contact-webhook"],
"globalSecret": "my-global-secret"
}
}'

Remove specific webhooks from your account:

Terminal window
curl -X DELETE https://api.sendblue.co/api/v2/account/webhooks \
-H "sb-api-key-id: YOUR_API_KEY" \
-H "sb-api-secret-key: YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"webhooks": ["https://example.com/webhook-to-delete"],
"type": "receive"
}'

SendBlue supports multiple ways to secure your webhook endpoints:

  • Per-webhook secret: Set a secret on individual webhook objects
  • Global secret: Set a globalSecret that applies to all webhooks
  • Legacy secret: The secret field at the root level (older format)

When you configure a secret, SendBlue will include it in the webhook request headers, allowing you to verify that the request is genuinely from SendBlue.

// Example: Setting up a webhook with a secret
const response = await fetch('https://api.sendblue.co/api/v2/account/webhooks', {
method: 'POST',
headers: {
'sb-api-key-id': 'YOUR_API_KEY',
'sb-api-secret-key': 'YOUR_API_SECRET',
'Content-Type': 'application/json'
},
body: JSON.stringify({
webhooks: [
{
url: 'https://myapp.com/webhooks/sendblue',
secret: 'my-secure-secret-123'
}
],
type: 'receive'
})
});

When you receive an inbound message, SendBlue will POST to your configured receive webhook with the following payload:

{
"accountEmail": "[email protected]",
"content": "Hello!",
"media_url": "https://example.com/image.jpg",
"is_outbound": false,
"status": "RECEIVED",
"message_handle": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
"date_sent": "2020-09-10T06:15:05.962Z",
"date_updated": "2020-09-10T06:15:14.115Z",
"from_number": "+19998887777",
"number": "+19998887777",
"to_number": "+15122164639",
"was_downgraded": false
}

For outbound messages, you can use the status_callback parameter when sending a message, or configure an outbound webhook to receive all outbound message status updates:

{
"accountEmail": "[email protected]",
"content": "Hello world!",
"is_outbound": true,
"status": "DELIVERED",
"error_code": null,
"error_message": null,
"message_handle": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
"date_sent": "2020-09-10T06:15:05.962Z",
"date_updated": "2020-09-10T06:15:14.115Z",
"from_number": "+15122164639",
"number": "+19998887777",
"to_number": "+19998887777",
"was_downgraded": false,
"plan": "blue"
}
FieldTypeDescription
accountEmailstringAssociated account email
contentstringMessage content
is_outboundbooleanTrue if message is sent, false if message is received
media_urlstringA CDN link to any media attached to the message
statusstringThe current status of the message
error_codeintError code (null if no error)
error_messagestringDescriptive error message (null if no error)
message_handlestringSendblue message handle
date_sentstringISO 8601 formatted date string of when message was created
date_updatedstringISO 8601 formatted date string of when message was last updated
from_numberstringE.164 formatted phone number of the message dispatcher
numberstringE.164 formatted phone number of your end-user
to_numberstringE.164 formatted phone number of the message recipient
was_downgradedbooleanTrue if the end user does not support iMessage
planstringValue of the Sendblue account plan

All webhook URLs must use HTTPS to ensure secure communication.

Your webhook endpoints should be idempotent, as they may receive duplicate events. Use the message_handle field to deduplicate events.

// Example: Idempotent webhook handler
const processedMessages = new Set();
app.post('/webhook', (req, res) => {
const { message_handle } = req.body;
if (processedMessages.has(message_handle)) {
return res.status(200).send('Already processed');
}
processedMessages.add(message_handle);
// Process the webhook...
res.status(200).send('OK');
});

Always verify that webhook requests are coming from SendBlue by checking the secret in the request headers.

  • Return 200-299 for successful processing
  • Return 410 Gone if you want SendBlue to automatically remove the webhook

Implement proper error handling and logging in your webhook endpoints to troubleshoot issues.

{
"status": "ERROR",
"message": "Unauthorized"
}

Authentication failed. Check your API credentials.

{
"status": "ERROR",
"message": "Missing or invalid webhooks array"
}

The request body is malformed or missing required fields.

{
"status": "ERROR",
"message": "Error message details"
}

An internal error occurred. Contact support if this persists.

// Add a simple webhook for receiving messages
const response = await fetch('https://api.sendblue.co/api/v2/account/webhooks', {
method: 'POST',
headers: {
'sb-api-key-id': 'YOUR_API_KEY',
'sb-api-secret-key': 'YOUR_API_SECRET',
'Content-Type': 'application/json'
},
body: JSON.stringify({
webhooks: ['https://myapp.com/webhooks/sendblue'],
type: 'receive'
})
});
const data = await response.json();
console.log(data);

Example 2: Multi-Type Webhook Configuration

Section titled “Example 2: Multi-Type Webhook Configuration”
// Configure webhooks for multiple event types
const response = await fetch('https://api.sendblue.co/api/v2/account/webhooks', {
method: 'PUT',
headers: {
'sb-api-key-id': 'YOUR_API_KEY',
'sb-api-secret-key': 'YOUR_API_SECRET',
'Content-Type': 'application/json'
},
body: JSON.stringify({
webhooks: {
receive: ['https://myapp.com/webhooks/receive'],
outbound: ['https://myapp.com/webhooks/outbound'],
call_log: ['https://myapp.com/webhooks/calls'],
contact_created: ['https://myapp.com/webhooks/contacts'],
globalSecret: 'my-global-secret'
}
})
});
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/sendblue', (req, res) => {
const {
content,
from_number,
message_handle,
is_outbound,
status
} = req.body;
console.log(`New message from ${from_number}: ${content}`);
console.log(`Message handle: ${message_handle}`);
console.log(`Status: ${status}`);
// Process the message here
// ...
// Always respond with 200 to acknowledge receipt
res.status(200).send('OK');
});
app.listen(3000, () => {
console.log('Webhook server running on port 3000');
});
  • Webhook URLs are automatically validated to ensure they are valid HTTPS URLs
  • The API maintains backward compatibility with legacy webhook formats
  • The receive webhook type is the most commonly used for inbound messages
  • You can configure multiple webhooks for the same event type for redundancy