Skooh.io Logo
Back to blog
IntegrationDeveloper TutorialApril 9, 20257 min

Intercom Webhooks to an Internal CRM Bridge Using Skooh

Sync Intercom conversations and tags to internal CRM systems in real-time.

Use Case

Your support team uses Intercom, but customer data lives in your internal CRM. When a conversation starts, gets tagged, or closes, you want your CRM updated automatically.

Skooh forwards Intercom webhooks to your internal CRM bridge service.

Setup

1. Create Skooh Endpoint

Create "Intercom CRM Sync" in Skooh.

2. Run the Skooh Proxy

Using the Desktop App:

  1. Download the Skooh Desktop App
  2. Enter your API key and hook token
  3. Set forwarding URL (e.g., `http://localhost:3000/webhooks/intercom\`)
  4. Click Connect

Using Docker:

docker run -d \\
  --name skooh-intercom \\
  -e SKOOH_TOKEN=intercom-crm \\
  -e SKOOH_API_KEY=your_api_key \\
  -e FORWARD_URL=http://crm-bridge:3000/webhooks/intercom \\
  --restart unless-stopped \\
  skooh/proxy

3. Configure Intercom

Note: See Intercom's Webhook documentation for current setup instructions.

In Intercom Developer Hub:

  1. Create or select your app
  2. Go to Webhooks
  3. Add your Skooh URL
  4. Select topics:
    • `conversation.user.created`
    • `conversation.user.replied`
    • `conversation.admin.replied`
    • `conversation.admin.closed`
    • `contact.tag.created`
    • `contact.tag.deleted`

Handling Intercom Webhooks

app.post('/webhooks/intercom', express.json(), async (req, res) => {
  const { topic, data } = req.body;
  
  // Verify webhook signature
  if (!verifyIntercomSignature(req)) {
    return res.status(401).send('Invalid signature');
  }
  
  switch (topic) {
    case 'conversation.user.created':
      await handleNewConversation(data);
      break;
      
    case 'conversation.admin.closed':
      await handleConversationClosed(data);
      break;
      
    case 'contact.tag.created':
      await handleTagAdded(data);
      break;
      
    case 'contact.tag.deleted':
      await handleTagRemoved(data);
      break;
  }
  
  res.status(200).send('OK');
});

Syncing Conversations to CRM

async function handleNewConversation(data) {
  const { item: conversation } = data;
  
  // Extract customer info
  const customer = conversation.user;
  const email = customer.email;
  
  // Find customer in CRM
  const crmCustomer = await crmClient.findByEmail(email);
  
  if (crmCustomer) {
    // Create interaction record
    await crmClient.createInteraction({
      customerId: crmCustomer.id,
      type: 'support_conversation',
      channel: 'intercom',
      externalId: conversation.id,
      subject: conversation.source?.subject || 'Support Request',
      createdAt: new Date(conversation.created_at * 1000)
    });
    
    // Update last contact date
    await crmClient.updateCustomer(crmCustomer.id, {
      lastContactDate: new Date()
    });
  }
}

Syncing Tags

Tags in Intercom → segments in CRM:

async function handleTagAdded(data) {
  const { item: tagEvent } = data;
  const contact = tagEvent.contact;
  const tag = tagEvent.tag;
  
  const crmCustomer = await crmClient.findByEmail(contact.email);
  
  if (crmCustomer) {
    // Map Intercom tag to CRM segment
    const segmentMap = {
      'vip': 'high_value_customer',
      'churning': 'at_risk',
      'enterprise': 'enterprise_tier',
      'product_feedback': 'feedback_provider'
    };
    
    const segment = segmentMap[tag.name];
    if (segment) {
      await crmClient.addToSegment(crmCustomer.id, segment);
    }
  }
}

Verifying Intercom Webhooks

const crypto = require('crypto');

function verifyIntercomSignature(req) {
  const signature = req.headers['x-hub-signature'];
  if (!signature) return false;
  
  const hmac = crypto.createHmac('sha1', process.env.INTERCOM_CLIENT_SECRET);
  const digest = 'sha1=' + hmac.update(JSON.stringify(req.body)).digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(digest)
  );
}

Two-Way Sync

Update Intercom when CRM changes:

// When customer upgraded in CRM
async function onCustomerUpgraded(customer) {
  // Add VIP tag in Intercom
  await intercomClient.tags.tag({
    name: 'vip',
    users: [{ email: customer.email }]
  });
}

Testing with Replay

  1. Create a test conversation in Intercom
  2. Find the webhook in Skooh
  3. Replay to test your CRM bridge
  4. Verify data appears in CRM
  5. Replay again after fixing bugs

Set up Intercom sync →

Written by Skooh Team

Share:

Ready to try Skooh?

Start receiving webhooks in your local environment in under 5 minutes.

Skooh | Intercom Webhooks to an Internal CRM Bridge Using Skooh