Intercom Deploy Integration
Overview
Deploy Intercom-powered applications to Vercel, Fly.io, or Google Cloud Run with proper secret management, webhook endpoint configuration, and health checks.
Prerequisites
- Intercom production access token
- Platform CLI installed (
vercel,flyctl, orgcloud) - Application with Intercom integration ready for deployment
Instructions
Step 1: Vercel Deployment
# Add Intercom secrets to Vercel
vercel env add INTERCOM_ACCESS_TOKEN production
vercel env add INTERCOM_WEBHOOK_SECRET production
# Deploy to production
vercel --prod
API Route for Webhooks (Vercel Serverless):
// api/webhooks/intercom.ts (Vercel serverless function)
import crypto from "crypto";
export const config = { api: { bodyParser: false } };
export default async function handler(req: any, res: any) {
if (req.method !== "POST") return res.status(405).end();
const chunks: Buffer[] = [];
for await (const chunk of req) chunks.push(chunk);
const body = Buffer.concat(chunks);
// Verify signature
const signature = req.headers["x-hub-signature"] as string;
const expected = "sha1=" + crypto
.createHmac("sha1", process.env.INTERCOM_WEBHOOK_SECRET!)
.update(body)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(signature || ""), Buffer.from(expected))) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(body.toString());
console.log(`Intercom webhook: ${event.topic}`);
// Process within 5s (Intercom timeout)
// For long processing, queue the event and return immediately
res.status(200).json({ received: true });
}
vercel.json:
{
"functions": {
"api/webhooks/intercom.ts": {
"maxDuration": 10
}
}
}
Step 2: Fly.io Deployment
# fly.toml
app = "my-intercom-app"
primary_region = "iad"
[env]
NODE_ENV = "production"
[http_service]
internal_port = 3000
force_https = true
auto_stop_machines = false # Keep running for webhooks
auto_start_machines = true
[[http_service.checks]]
grace_period = "10s"
interval = "30s"
method = "GET"
path = "/health"
timeout = "5s"
# Set secrets
fly secrets set INTERCOM_ACCESS_TOKEN="dG9rOi4uLg=="
fly secrets set INTERCOM_WEBHOOK_SECRET="your-secret"
# Deploy
fly deploy
# Verify health
fly status
curl https://my-intercom-app.fly.dev/health
Step 3: Google Cloud Run
#!/bin/bash
PROJECT_ID="${GOOGLE_CLOUD_PROJECT}"
SERVICE="intercom-service"
REGION="us-central1"
# Store secrets in Secret Manager
echo -n "$INTERCOM_ACCESS_TOKEN" | \
gcloud secrets create intercom-token --data-file=- --replication-policy=automatic
echo -n "$INTERCOM_WEBHOOK_SECRET" | \
gcloud secrets create intercom-webhook-secret --data-file=- --replication-policy=automatic
# Build and deploy
gcloud builds submit --tag gcr.io/$PROJECT_ID/$SERVICE
gcloud run deploy $SERVICE \
--image gcr.io/$PROJECT_ID/$SERVICE \
--region $REGION \
--platform managed \
--allow-unauthenticated \
--set-secrets="INTERCOM_ACCESS_TOKEN=intercom-token:latest,INTERCOM_WEBHOOK_SECRET=intercom-webhook-secret:latest" \
--min-instances=1 \
--timeout=60
Step 4: Health Check Endpoint
// src/routes/health.ts
import { IntercomClient, IntercomError } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
export async function healthCheck(): Promise<{
status: string;
services: { intercom: { connected: boolean; latencyMs: number; error?: string } };
}> {
const start = Date.now();
try {
await client.admins.list();
return {
status: "healthy",
services: {
intercom: { connected: true, latencyMs: Date.now() - start },
},
};
} catch (err) {
const latencyMs = Date.now() - start;
const error = err instanceof IntercomError
? `${err.statusCode}: ${err.message}`
: (err as Error).message;
return {
status: "degraded",
services: {
intercom: { connected: false, latencyMs, error },
},
};
}
}
Step 5: Register Webhook URL
After deploying, configure the webhook URL in Intercom:
- Go to Developer Hub > Webhooks
- Set endpoint URL:
https://your-domain.com/api/webhooks/intercom - Select topics:
conversation.user.created,contact.created, etc. - Copy the webhook signing secret to your platform secrets
- Send a test notification to verify
Webhook Topics Reference
| Topic | Fires When |
|-------|-----------|
| conversation.user.created | New conversation from contact |
| conversation.user.replied | Contact replies |
| conversation.admin.replied | Admin replies |
| conversation.admin.closed | Conversation closed |
| contact.created | New contact created |
| contact.signed_up | Lead converts to user |
| contact.tag.created | Tag applied to contact |
| user.created | New user (legacy topic) |
Error Handling
| Issue | Cause | Solution | |-------|-------|----------| | Webhook 401 | Signature mismatch | Verify secret matches Developer Hub | | Cold start timeout | Serverless spin-up | Set min instances > 0 | | Secret not found | Missing config | Verify secrets with platform CLI | | Health check failing | Token invalid in prod | Verify production token | | Webhook delivery fails | 5s timeout exceeded | Queue events, process async |
Resources
Next Steps
For webhook handling patterns, see intercom-webhooks-events.