Intercom Integration
Receive and route Intercom webhooks for conversations, contacts, companies, and user events.
Setup
1. Create a Source in Hookbase
curl -X POST https://api.hookbase.app/api/sources \
-H "Authorization: Bearer whr_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Intercom Production",
"slug": "intercom",
"verificationConfig": {
"type": "hmac",
"secret": "your-intercom-client-secret",
"algorithm": "sha1",
"header": "X-Hub-Signature",
"signaturePrefix": "sha1=",
"encoding": "hex"
}
}'Save your webhook URL:
https://api.hookbase.app/ingest/{orgSlug}/intercom2. Configure Intercom Webhook
- Go to the Intercom Developer Hub
- Select your app (or create one)
- Navigate to Webhooks in the left sidebar
- Enter your Hookbase webhook URL in the Webhook URL field
- Select the topics you want to receive (e.g.,
conversation.user.created,contact.created) - Click Save
- Copy your app's Client Secret from the Basic Information page
- Update your Hookbase source with this secret
TIP
Your Client Secret is found under Basic Information in the Intercom Developer Hub. This is the secret used to sign webhook payloads, not your access token.
3. Create Routes
# Create destination for your conversation handler
curl -X POST https://api.hookbase.app/api/destinations \
-H "Authorization: Bearer whr_your_api_key" \
-d '{"name": "Support Service", "url": "https://api.myapp.com/webhooks/intercom"}'
# Create route
curl -X POST https://api.hookbase.app/api/routes \
-H "Authorization: Bearer whr_your_api_key" \
-d '{"name": "Intercom to Support Service", "sourceId": "src_...", "destinationIds": ["dst_..."]}'Signature Verification
Intercom signs webhooks with HMAC-SHA1 using your app's client secret. The signature is sent in the X-Hub-Signature header with a sha1= prefix:
X-Hub-Signature: sha1=d3b07384d113edec49eaa6238ad5ff00b8d257e5Hookbase automatically verifies this signature when configured:
{
"verificationConfig": {
"type": "hmac",
"secret": "your-intercom-client-secret",
"algorithm": "sha1",
"header": "X-Hub-Signature",
"signaturePrefix": "sha1=",
"encoding": "hex"
}
}WARNING
Make sure you use the Client Secret from your Intercom app's Basic Information page, not the access token. The client secret is the key used to compute the HMAC signature.
Common Events
conversation.user.created
Triggered when a user starts a new conversation.
{
"type": "notification_event",
"app_id": "abc123de",
"topic": "conversation.user.created",
"id": "notif_12345-67890",
"created_at": 1710432000,
"delivery_status": "pending",
"data": {
"type": "notification_event_data",
"item": {
"type": "conversation",
"id": "12345678901",
"created_at": 1710432000,
"updated_at": 1710432000,
"source": {
"type": "conversation",
"id": "12345678901",
"delivered_as": "customer_initiated",
"body": "<p>Hi, I need help with my account settings.</p>",
"author": {
"type": "user",
"id": "6543210abc",
"name": "Jane Smith",
"email": "[email protected]"
}
},
"contacts": {
"type": "contact.list",
"contacts": [
{
"type": "contact",
"id": "6543210abc",
"external_id": "user_98765"
}
]
},
"state": "open",
"open": true,
"read": false,
"tags": {
"type": "tag.list",
"tags": []
}
}
}
}conversation.admin.replied
Triggered when an admin or bot replies to a conversation.
{
"type": "notification_event",
"app_id": "abc123de",
"topic": "conversation.admin.replied",
"id": "notif_12345-67891",
"created_at": 1710432600,
"data": {
"type": "notification_event_data",
"item": {
"type": "conversation",
"id": "12345678901",
"created_at": 1710432000,
"updated_at": 1710432600,
"conversation_parts": {
"type": "conversation_part.list",
"conversation_parts": [
{
"type": "conversation_part",
"id": "98765432",
"part_type": "comment",
"body": "<p>Hi Jane, I'd be happy to help with your account settings!</p>",
"author": {
"type": "admin",
"id": "1234567",
"name": "Support Agent",
"email": "[email protected]"
},
"created_at": 1710432600
}
]
},
"state": "open",
"open": true
}
}
}conversation.admin.closed
Triggered when an admin closes a conversation.
{
"type": "notification_event",
"app_id": "abc123de",
"topic": "conversation.admin.closed",
"id": "notif_12345-67892",
"created_at": 1710435000,
"data": {
"type": "notification_event_data",
"item": {
"type": "conversation",
"id": "12345678901",
"created_at": 1710432000,
"updated_at": 1710435000,
"state": "closed",
"open": false,
"tags": {
"type": "tag.list",
"tags": [
{ "type": "tag", "id": "456", "name": "resolved" }
]
}
}
}
}contact.created
Triggered when a new contact is created.
{
"type": "notification_event",
"app_id": "abc123de",
"topic": "contact.created",
"id": "notif_12345-67893",
"created_at": 1710436000,
"data": {
"type": "notification_event_data",
"item": {
"type": "contact",
"id": "6543210def",
"role": "user",
"external_id": "user_11111",
"email": "[email protected]",
"name": "Alex Johnson",
"phone": "+1-555-0123",
"avatar": "https://example.com/avatar.jpg",
"signed_up_at": 1710436000,
"created_at": 1710436000,
"updated_at": 1710436000,
"custom_attributes": {
"plan": "pro",
"company_size": "50-100"
},
"companies": {
"type": "company.list",
"companies": [
{
"type": "company",
"id": "comp_98765",
"name": "Acme Corp"
}
]
},
"location": {
"city": "San Francisco",
"country": "United States",
"region": "California"
},
"tags": {
"type": "tag.list",
"tags": [
{ "type": "tag", "id": "789", "name": "trial-user" }
]
}
}
}
}user.tag.created
Triggered when a tag is added to a user.
{
"type": "notification_event",
"app_id": "abc123de",
"topic": "user.tag.created",
"id": "notif_12345-67894",
"created_at": 1710437000,
"data": {
"type": "notification_event_data",
"item": {
"type": "tag",
"id": "321",
"name": "vip-customer"
},
"user": {
"type": "user",
"id": "6543210abc",
"email": "[email protected]",
"name": "Jane Smith",
"user_id": "user_98765"
}
}
}Intercom Webhook Topics
| Category | Topics |
|---|---|
| Conversations | conversation.user.created, conversation.user.replied, conversation.admin.replied, conversation.admin.closed, conversation.admin.opened, conversation.admin.snoozed, conversation.admin.unsnoozed, conversation.admin.assigned, conversation.admin.noted, conversation.admin.single.created, conversation.rating.added, conversation.rating.remarked |
| Contacts | contact.created, contact.updated, contact.deleted, contact.signed_up, contact.tag.created, contact.tag.deleted |
| Users | user.created, user.deleted, user.email.updated, user.tag.created, user.tag.deleted |
| Companies | company.created |
| Visitors | visitor.signed_up |
Transform Examples
Slack Alert for New Conversations
function transform(payload) {
const conversation = payload.data.item;
const author = conversation.source?.author || {};
const body = (conversation.source?.body || '')
.replace(/<[^>]*>/g, '');
return {
blocks: [
{
type: "header",
text: {
type: "plain_text",
text: "New Intercom Conversation"
}
},
{
type: "section",
fields: [
{
type: "mrkdwn",
text: `*From:*\n${author.name || 'Unknown'} (${author.email || 'no email'})`
},
{
type: "mrkdwn",
text: `*Conversation ID:*\n${conversation.id}`
}
]
},
{
type: "section",
text: {
type: "mrkdwn",
text: `*Message:*\n${body.substring(0, 500)}`
}
},
{
type: "actions",
elements: [
{
type: "button",
text: {
type: "plain_text",
text: "Open in Intercom"
},
url: `https://app.intercom.com/a/apps/${payload.app_id}/conversations/${conversation.id}`
}
]
}
]
};
}Database Format
function transform(payload) {
const topic = payload.topic;
const item = payload.data.item;
// Handle conversation events
if (topic.startsWith('conversation.')) {
const author = item.source?.author || {};
return {
intercom_event_id: payload.id,
event_type: topic,
conversation_id: item.id,
state: item.state,
author_type: author.type,
author_id: author.id,
author_email: author.email,
author_name: author.name,
app_id: payload.app_id,
created_at: new Date(payload.created_at * 1000).toISOString()
};
}
// Handle contact/user events
if (topic.startsWith('contact.') || topic.startsWith('user.')) {
return {
intercom_event_id: payload.id,
event_type: topic,
contact_id: item.id,
external_id: item.external_id || item.user_id,
email: item.email,
name: item.name,
role: item.role,
custom_attributes: item.custom_attributes || {},
app_id: payload.app_id,
created_at: new Date(payload.created_at * 1000).toISOString()
};
}
// Fallback for other events
return {
intercom_event_id: payload.id,
event_type: topic,
item_type: item.type,
item_id: item.id,
app_id: payload.app_id,
created_at: new Date(payload.created_at * 1000).toISOString()
};
}Alert for Closed Conversations
function transform(payload) {
const conversation = payload.data.item;
const tags = (conversation.tags?.tags || [])
.map(t => t.name)
.join(', ');
return {
channel: "#support-resolved",
username: "Intercom Bot",
icon_emoji: ":white_check_mark:",
attachments: [{
color: "good",
title: "Conversation Closed",
fields: [
{ title: "Conversation ID", value: conversation.id, short: true },
{ title: "State", value: conversation.state, short: true },
{ title: "Tags", value: tags || "None", short: false }
],
footer: `App ${payload.app_id}`,
ts: payload.created_at
}]
};
}Filter Examples
Conversation Events Only
{
"name": "Conversation Events",
"logic": "and",
"conditions": [
{
"field": "topic",
"operator": "starts_with",
"value": "conversation."
}
]
}New Conversations from Users
{
"name": "User-Created Conversations",
"logic": "and",
"conditions": [
{
"field": "topic",
"operator": "equals",
"value": "conversation.user.created"
}
]
}Contact Events
{
"name": "Contact Events",
"logic": "or",
"conditions": [
{
"field": "topic",
"operator": "starts_with",
"value": "contact."
},
{
"field": "topic",
"operator": "starts_with",
"value": "user."
}
]
}Closed Conversations with Tags
{
"name": "Tagged Closures",
"logic": "and",
"conditions": [
{
"field": "topic",
"operator": "equals",
"value": "conversation.admin.closed"
},
{
"field": "data.item.tags.tags",
"operator": "not_empty",
"value": ""
}
]
}Headers
Intercom sends these headers with webhooks:
| Header | Description |
|---|---|
X-Hub-Signature | HMAC-SHA1 signature with sha1= prefix |
Content-Type | Always application/json |
X-Intercom-App-Id | Your Intercom app ID |
User-Agent | Intercom user agent string |
Troubleshooting
Signature Verification Failed
- Verify you're using the Client Secret from your Intercom app's Basic Information page
- Do not use the access token or API key — only the client secret is used for signing
- Ensure the verification config uses
algorithm: "sha1"andsignaturePrefix: "sha1=" - Check that the secret has no leading or trailing whitespace
Webhooks Not Arriving
- Check the Intercom Developer Hub for webhook delivery logs
- Verify the webhook URL is correct and publicly accessible
- Ensure you have selected the correct topics in Intercom's webhook settings
- Check that your Intercom app has the required permissions for the subscribed topics
Missing Events
- Verify the specific topics are enabled in your Intercom webhook configuration
- Check that filters aren't blocking expected events
- Some events require specific Intercom plans — verify your plan supports the topic
- Intercom may batch or delay certain low-priority events
Duplicate Events
- Intercom may retry failed webhook deliveries
- Implement idempotency using the notification
idfield - Enable deduplication using the event ID:
curl -X PATCH .../sources/src_intercom \
-d '{"dedupEnabled": true, "dedupStrategy": "provider_id"}'Best Practices
- Verify signatures: Always configure HMAC-SHA1 verification to ensure webhooks are from Intercom
- Handle HTML content: Conversation bodies contain HTML — strip tags when forwarding to plain-text destinations
- Use deduplication: Intercom retries failed deliveries, so enable dedup to prevent duplicates
- Subscribe selectively: Only subscribe to topics you need to reduce noise and processing overhead
- Handle idempotently: Use the notification
idto detect and skip already-processed events - Monitor rate limits: High-volume Intercom workspaces may generate significant webhook traffic — monitor delivery queues