---
title: "Test Intercom Webhooks Locally | WebhookRelay"
meta:
  "og:description": "Test Intercom webhooks locally on localhost without deploying. Inspect the real topic payload, forward to your handler, and verify the X-Hub-Signature."
  "og:title": "Test Intercom Webhooks Locally"
  description: "Test Intercom webhooks locally on localhost without deploying. Inspect the real topic payload, forward to your handler, and verify the X-Hub-Signature."
---

![Stripes](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/images/stripes.svg)

# **Test Intercom Webhooks Locally**

Test Intercom webhooks locally on localhost without deploying. Inspect the real topic payload, forward to your handler, and verify the X-Hub-Signature.

![Test Intercom Webhooks Locally (Intercom Webhook on localhost)](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/images/blog/heroes/localhost.jpg)

You are building an Intercom integration — syncing contacts, reacting to new conversations, piping events into your own product — and you need to see your handler react to a real `conversation.user.created` or `contact.created` notification. The problem is immediate: Intercom will only POST to a **public HTTPS URL**, and your handler is running on `localhost:8080`. Intercom has no way to reach it.

The usual workarounds are painful. Deploying to a staging server for every code change is slow. Copying a sample payload from the docs into curl gives you a _guess_ at the real request, not the actual `topic`, `data`, and `X-Hub-Signature` Intercom sends. What you want is to **test Intercom webhooks locally** — real notifications, hitting your local handler, with a URL that does not change every time you restart.

This guide shows how to do exactly that.

## [Why testing Intercom webhooks locally is tricky](#why-testing-intercom-webhooks-locally-is-tricky)

A webhook is just an HTTP request that Intercom sends to a URL when something happens in your workspace — a new conversation, a contact update, a tag applied. Intercom sits on the public internet; your dev machine usually does not. It is behind a router, a corporate firewall, or both, with no public IP and no inbound ports open.

So you need something in the middle: a public HTTPS endpoint Intercom can hit, that relays each request down to your laptop without you opening a single firewall port. That is what [Webhook Relay](https://my.webhookrelay.com/register) does — and unlike a random tunnel URL, the endpoint is **stable**, so you configure Intercom once and never touch it again.

There is one Intercom-specific wrinkle: when you save a webhook URL in the Developer Hub, Intercom sends a **HEAD request to validate it** before it will accept the subscription. Your endpoint must respond successfully to that check, and it must be **HTTPS**. Webhook Relay endpoints are HTTPS and answer the validation probe, so the URL is accepted right away.

## [Step 1: Inspect the real payload with Webhook Bin](#step-1-inspect-the-real-payload-with-webhook-bin)

Before you write any handler code, find out what Intercom actually sends. Open the free [Webhook Bin](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/webhook-bin/) — no signup — and you get an instant public HTTPS URL.

1. Copy the Webhook Bin URL.
2. Go to the [Intercom Developer Hub](https://app.intercom.com/a/apps/_/developer-hub), open your app, and in **Configure → Webhooks** paste the URL as the endpoint.
3. Subscribe to the topics you care about — for example `conversation.user.created`, `contact.created`, or `contact.tag.created`.
4. Save. Intercom validates the URL with a HEAD request, then starts delivering notifications.

Trigger a real action in your workspace (start a conversation, create a contact) and inspect the captured request in Webhook Bin: the full JSON body, the query string, and every header. You will see the notification envelope Intercom uses — `type: notification_event`, the `topic`, your `app_id`, and a `data` object wrapping the affected Intercom resource — plus the `X-Hub-Signature` header.

Now you know the exact shape of the data before writing a line of code. For more on this approach, see [How to test webhooks](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/blog/how-to-test-webhooks/) and [What is a webhook](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/blog/what-is-webhook/).

## [Step 2: Forward the notifications to localhost with the relay agent](#step-2-forward-the-notifications-to-localhost-with-the-relay-agent)

Once you know the payload, route those same notifications into your local handler. [Sign up for Webhook Relay](https://my.webhookrelay.com/register), install the `relay` agent (CLI or Docker), and create a bucket — say `intercom`. The bucket gives you a stable public input endpoint.

Start forwarding to your local server:

```
relay forward --bucket intercom http://localhost:8080/webhook
```

The agent opens an **outbound** connection to Webhook Relay and streams every incoming request down to `http://localhost:8080/webhook`. Because the connection is outbound, there are **no firewall ports to open and no public IP needed** — this works from your laptop, behind a corporate proxy, or inside a Kubernetes cluster. Running in Docker? The same command works in the official `webhookrelay/webhookrelayd` image. Full details are in the [localhost forwarding docs](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/docs/webhooks/internal/localhost/).

Now set the Intercom webhook endpoint in **Configure → Webhooks** to your Webhook Relay endpoint (or just create it there from the start). Trigger an event and watch it arrive on `localhost`.

## [Intercom-specific configuration and quirks](#intercom-specific-configuration-and-quirks)

A few Intercom details worth knowing:

- **Where to configure it:** webhooks live on a **Developer Hub app**, not in the main workspace settings. Open your app and go to **Configure → Webhooks**. You also need the matching permissions enabled on the app's Authorization page before some topics will deliver.
- **Topics, not "all events":** you explicitly subscribe to topics such as `conversation.user.created`, `conversation.admin.replied`, `contact.created`, and `contact.tag.created`. Use the `topic` field in the body to branch in your handler.
- **HTTPS + HEAD validation:** the endpoint must be HTTPS and must answer Intercom's HEAD validation request, or the subscription will not save. Webhook Relay handles both.
- **Respond fast with 200:** Intercom expects an HTTP `200` within **5 seconds** and will **retry** otherwise. Acknowledge receipt immediately, then do slow work asynchronously. Sustained error responses will pause or suspend your subscription.
- **Payload envelope:** the body always wraps the resource in a `notification_event` shape with a `data.item` object — your handler reads `topic` to know what happened and `data.item` for the resource.

## [Step 3: Verify the Intercom webhook signature](#step-3-verify-the-intercom-webhook-signature)

Intercom signs every notification so you can confirm it really came from Intercom. It computes an **HMAC-SHA1** of the raw request body using your **app's client secret** as the key, hex-encodes the result, and sends it in the **`X-Hub-Signature`** header, formatted as `sha1=...`.

Your handler should recompute the HMAC-SHA1 over the **raw** body (the exact bytes received, before any JSON parser reshapes them) and compare in constant time before trusting the payload. Note this is **SHA-1**, not the SHA-256 some other providers use — match the algorithm exactly or the digest will never line up.

To sanity-check your implementation, paste a captured body, your client secret, and the received signature into the free [HMAC signature verifier](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/hmac-verification/). For language-specific code and the common pitfalls (reading the body after a JSON parser has consumed it, timing-safe comparison), read [Verify a webhook signature](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/blog/verify-webhook-signature/).

## [Replay and iterate](#replay-and-iterate)

This is where local development gets fast:

- **Replay from Webhook Relay** — past requests are stored on your bucket, so you can resend a captured notification against your handler without touching Intercom at all.
- **Iterate on your handler** by editing code and replaying the same delivery until it behaves correctly. No deploys just to test a single code path.

Because the Webhook Relay endpoint is stable, you can stop and restart the agent, reboot your machine, or come back next week — the Intercom configuration never needs to change.

## [Get started](#get-started)

1. Inspect the real payload in the free [Webhook Bin](https://webhookrelay.com/blog/receive-intercom-webhooks-locally/webhook-bin/) — no signup needed.
2. [Create a Webhook Relay account](https://my.webhookrelay.com/register), install the agent, and run `relay forward --bucket intercom http://localhost:8080/webhook`.
3. Point your Intercom Developer Hub webhook at the stable endpoint, trigger an event, and watch it hit `localhost`.

You will be testing real Intercom topics against your local handler in a few minutes — no deploys, no open firewall ports, and a URL you configure exactly once.