unauthorize
'Manage Intercom contacts: create, search, update, merge leads into users.
ReadWriteEditBash(npm:*)Grep
Intercom Contacts & Contact Management
Overview
Primary workflow for managing Intercom contacts. Covers creating users and leads, searching with filters, updating custom attributes, merging leads into users, and listing segments. This SKILL.md gives you the high-level workflow and the first example; drill into references/implementation.md for the full step-by-step code and references/examples.md for end-to-end flows.
Prerequisites
- Completed
intercom-install-auth setup
- Understanding of Intercom contact model (users vs leads)
- Valid API credentials with contacts read/write scope
Instructions
The contact workflow is six operations against the intercom-client SDK. Instantiate the client once, then call the operation you need:
import { IntercomClient } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
// Create an identified user (has external_id)
const user = await client.contacts.create({
role: "user",
externalId: "customer-9001",
email: "alice@acme.com",
name: "Alice Johnson",
customAttributes: { plan: "enterprise" },
});
The six operations, in the order you typically reach for them:
- Create contacts —
contacts.create with role: "user" (identified, needs externalId) or role: "lead" (anonymous).
- Search contacts —
contacts.search with a single filter or a compound AND/OR query, plus pagination and sort.
- Update a contact —
contacts.update by contactId to change name or custom attributes.
- Merge a lead into a user —
contacts.merge({ from: leadId, into: userId }); the lead's conversations, events, and tags transfer to the user.
- List segments —
contacts.listSegments({ contactId }) to see which segments a contact belongs to.
- Paginate all contacts —
contacts.list with startingAfter cursor to stream the full contact base.
Full code for every step, including compound-search filters and the async-generator pagination helper, is in references/implementation.md.
Output
Each operation returns a typed response from the SDK:
create / update — a single contact object: { type: "contact", id, role, email, name, customAttributes, created_at, ... }. The id is the Intercom-generated handle you pass to later calls.
'Manage Intercom conversations: create, reply, close, snooze, assign,.
ReadWriteEditBash(npm:*)Grep
Intercom Conversations & Messaging
Overview
Manage the full conversation lifecycle: create, reply (as admin or contact), assign to teams, close, snooze, and tag. Conversations contain threaded "parts" including messages, notes, and assignments.
This SKILL.md gives you the high-level workflow and the essential skeleton. The complete step-by-step code for all seven operations lives in references/implementation.md; realistic end-to-end scenarios are in references/examples.md.
Prerequisites
- Completed
intercom-install-auth setup (provides the INTERCOMACCESSTOKEN)
- Admin ID (from
client.admins.list())
- Contact IDs for conversation participants
Authentication
All calls authenticate with a bearer access token supplied to the SDK client — see intercom-install-auth for how to obtain and store it. Read it from the environment, never hard-code it:
import { IntercomClient } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
The raw runassignmentrules endpoint (Step 3) uses the same token as an Authorization: Bearer header.
Instructions
The workflow is seven operations against client.conversations.*. Reach for the one you need — they are independent once you have a conversation ID.
- Create —
conversations.create({ from, body }) opens a conversation from a contact and returns its conversationId.
- Reply —
conversations.reply(...) adds a part. type: "admin" is customer-visible, type: "note" is internal-only, type: "user" is a contact reply.
- Assign —
conversations.assign(...) routes to an admin (type: "admin") or team (type: "team"); or POST runassignmentrules for auto-routing.
- Close / snooze / reopen —
conversations.close(...), conversations.snooze({ snoozedUntil }) (Unix seconds), and conversations.open(...).
- Tag —
conversations.attachTag(...) / detachTag(...).
- Retrieve —
conversations.find(...) returns state, assignee, and the conversationParts thread.
- List / search —
conversations.list() or conversations.search({ query, pagination, sort }) with AND/OR field filters.
Essential skeleton (create then reply); see references/implementation.md for every step in full:<
'Optimize Intercom API costs through caching, request reduction, and.
ReadGrep
Intercom Cost Tuning
Overview
Reduce Intercom API costs through smart caching, search optimization, webhook-driven architecture, and usage monitoring. Intercom pricing is primarily seat-based and feature-based, but API efficiency reduces infrastructure costs and avoids rate limits.
Intercom Pricing Model
| Component |
Pricing Basis |
Cost Driver |
| Seats |
Per agent/month |
Number of teammates |
| Fin AI Agent |
Per resolution |
AI-handled conversations |
| Proactive Support |
Per message sent |
Outbound messages volume |
| Help Center |
Included |
N/A |
| API |
Included (rate-limited) |
Request volume determines infra cost |
Key insight: The API itself is free to use, but hitting rate limits (10K req/min) forces you to build queuing infrastructure. Reducing requests saves engineering time and infrastructure costs.
Prerequisites
- An Intercom workspace with an access token and the Node/TypeScript Intercom client installed.
lru-cache available for the contact-caching step (npm install lru-cache).
- A public HTTPS endpoint to receive webhooks (Step 2) if you want to eliminate polling.
- Read access to the integration source so you can audit call sites: use Grep to find polling loops (
setInterval, .list() and Read to inspect the surrounding call site before refactoring.
Instructions
Work top-down — Steps 2-4 remove the most requests for the least code; Steps 1 and 6 confirm and protect the gains. Full copy-paste code for every step is in references/implementation.md.
- Audit current API usage. Instrument every call with an
IntercomUsageTracker that counts calls and average latency per endpoint, then prints a rate estimate against the 10K req/min limit. You cannot cut what you have not measured.
- Replace polling with webhooks. A 30-second poll loop costs ~2,880 requests/day per check; a webhook subscription costs zero and fires instantly:
app.post("/webhooks/intercom", (req, res) => {
const n = req.body;
if (n.topic === "conversation.user.created") handleNewConversation(n.data.item);
res.status(200).json({ received: true });
});
- Cache contact lookups. Wrap
contacts.find in an LRU cache (10-min TTL) and invalidate entries on contact.updated webhooks so repeat reads never hit the
'Implement Intercom data handling for GDPR, contact export, data retention,.
ReadWriteEdit
Intercom Data Handling
Overview
Handle sensitive contact data in Intercom integrations with GDPR/CCPA compliance:
data export via the Data Export API, contact deletion with an audit trail, PII
redaction in logs, and data retention policies. This skill gives you a lean map of
the five workflows here; the full copy-ready TypeScript lives in
references/implementation.md and worked usage in
references/examples.md.
Prerequisites
- Understanding of GDPR/CCPA requirements
intercom-client SDK installed
- Database for audit logging
- Familiarity with Intercom's contact and conversation data model
Authentication
Every call authenticates with an Intercom access token via a Bearer header. Store
it as INTERCOMACCESSTOKEN in the environment — never hardcode it and never log
it:
import { IntercomClient } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
// Raw REST calls use: Authorization: `Bearer ${process.env.INTERCOM_ACCESS_TOKEN}`
Grant the token the minimum scopes needed (read contacts/conversations for export,
write/delete for erasure). Rotate it if it ever appears in a log or a diff.
Data Classification for Intercom
| Category |
Intercom Fields |
Handling |
| PII |
email, name, phone, location |
Encrypt at rest, redact in logs |
| Identifiers |
id, externalid, userid |
Use for lookups, no display |
| Conversation content |
body, conversation_parts |
May contain PII, scan before logging |
| Custom attributes |
User-defined |
Depends on content |
| System metadata |
createdat, updatedat, role |
Standard handling |
Instructions
The five workflows below compose into a compliant Intercom data lifecycle. Follow
the summary here, then open references/implementation.md
for the complete function bodies.
- DSAR export —
exportContactData(contactId) gathers the contact profile,
all conversations (with parts), tags, segments, and data events into one bundle.
This is the "give me all my data" request.
- Right to deletion (Article 17) —
deleteContactData(contactId) exports for
the audit trail first<
'Collect Intercom debug evidence for support tickets and troubleshooting.
Bash(grep:*)Bash(curl:*)Bash(tar:*)Bash(npm:*)Bash(node:*)
Intercom Debug Bundle
Overview
Collect diagnostic evidence for Intercom issues: API health, auth status, rate-limit headers, SDK version, platform incidents, and redacted logs — packaged as a timestamped tarball safe to attach to a support ticket. Most persistent failures are auth (401) or rate-limit (429) problems, so the bundle leads with the /me health check before collecting anything heavier.
Prerequisites
- Intercom access token exported as
INTERCOMACCESSTOKEN
curl and jq available
- Access to application logs (optional — the collector redacts them)
Instructions
Step 1: Confirm auth before collecting
Most failed bundles are a bad token. Confirm /me returns 200 first; if not, fix auth before running the full collector.
TOKEN="${INTERCOM_ACCESS_TOKEN:?set INTERCOM_ACCESS_TOKEN and re-run}"
curl -s -o /dev/null -w "Auth HTTP: %{http_code}\n" \
-H "Authorization: Bearer $TOKEN" \
https://api.intercom.io/me
# 200 = OK, 401 = regenerate the token in the Developer Hub
Step 2: Run the full bundle collector
When the quick check passes, run the seven-step collector. It writes token
status, auth JSON, rate-limit headers, platform status and active incidents,
environment/SDK info, endpoint latencies, and redacted logs into a timestamped
directory, then tars it up as intercom-debug-YYYYMMDD-HHMMSS.tar.gz. Tokens,
emails, and .env values are stripped before packaging.
See the complete intercom-debug-bundle.sh script (all seven steps) in
full implementation.
Step 3: Redact and review before sharing
The collector redacts as it goes, but review the tarball before attaching it to
a ticket. What to ALWAYS redact vs what is SAFE TO INCLUDE (with copy-paste
curl snippets for reading rate-limit headers and capturing a request_id)
lives in examples and redaction rules.
Output
intercom-debug-YYYYMMDD-HHMMSS.tar.gz containing:
summary.txt — token status, auth result, rate-limit headers, platform status, active incident count, environment, SDK version, and per-endpoint latency (/me, /contacts, /conversations, /admins)
logs-redacted.txt — recent Intercom-related log lines with tokens and emails masked (present only if logs/app.log exists)
config-redacted.txt — .env copy with all values masked (present only if .env exists)
Sensitive Data Policy
ALWAYS redact:
Deploy Intercom integrations to Vercel, Fly.
ReadWriteEditBash(vercel:*)Bash(fly:*)Bash(gcloud:*)
Intercom Deploy Integration
Overview
Deploy Intercom-powered applications to Vercel, Fly.io, or Google Cloud Run with proper
secret management, signed webhook endpoints, and health checks. The workflow is the same
across platforms — provision two secrets, deploy, wire a /health probe, then register
the webhook URL — and each platform's copy-ready code lives in
references/implementation.md.
Prerequisites
- Intercom production access token
- Platform CLI installed (
vercel, flyctl, or gcloud)
- Application with Intercom integration ready for deployment
Authentication
Two secrets drive every deployment. INTERCOMACCESSTOKEN authenticates API calls
(passed to the SDK as new IntercomClient({ token })); INTERCOMWEBHOOKSECRET is the
Developer Hub signing secret used to verify inbound webhook payloads (HMAC-SHA1 over the
raw body, compared against the X-Hub-Signature header). Store both in the platform's
secret store — never hardcode them: vercel env add, fly secrets set, or Cloud Run
Secret Manager. A mismatched webhook secret returns 401 Invalid signature; an invalid
token surfaces as a degraded health check rather than a hard failure.
Instructions
Pick the platform that matches your stack. Each step below shows the essential skeleton;
open references/implementation.md for the complete webhook
handler, vercel.json, fly.toml, Cloud Run deploy script, and shared health-check code.
Step 1: Choose a platform and provision secrets
- Vercel (serverless):
vercel env add INTERCOMACCESSTOKEN production then
vercel env add INTERCOMWEBHOOKSECRET production.
- Fly.io (long-running):
fly secrets set INTERCOMACCESSTOKEN=... INTERCOMWEBHOOKSECRET=....
- Cloud Run (container): store both in Secret Manager and mount with
--set-secrets.
Step 2: Write the signed webhook handler
Read the raw request body (disable body parsing), recompute the HMAC-SHA1 signature, and
compare with crypto.timingSafeEqual. Return within 5 seconds — queue slower work:
const expected = "sha1=" + crypto
.createHmac("sha1", process.env.INTERCOM_WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) return res.status(401).end();
Write this to api/webhooks
Configure Intercom enterprise OAuth, admin roles, and app-level access control.
ReadWriteEdit
Intercom Enterprise RBAC
Overview
Configure enterprise-grade access control for Intercom integrations with OAuth
scopes, admin role management, and app-level permission enforcement.
The workflow covers the full path: enumerate the workspace's admins and teams,
authorize a public app with least-privilege scopes, enforce per-operation
permissions at the application layer, route conversations to teams, and audit
sensitive admin actions.
The high-level workflow lives here; complete, copy-ready code for every step is in
references/implementation.md, and end-to-end
scenarios are in references/examples.md.
Prerequisites
- Intercom workspace with admin access
- Understanding of OAuth 2.0 flows
- For public apps: OAuth configured in Developer Hub
intercom-client installed and INTERCOMACCESSTOKEN (or OAuth client
credentials) available in the environment
Intercom Admin Roles
Intercom has built-in admin roles that control workspace access:
| Role |
API Access |
Capabilities |
| Owner |
Full |
All operations, billing, workspace settings |
| Admin |
Full |
Manage contacts, conversations, content |
| Agent |
Limited |
Reply to conversations, view contacts |
| Custom roles |
Configurable |
Enterprise plan feature |
These built-in roles govern access inside the Intercom UI and API. Map them onto
explicit permissions (Step 3) rather than trusting the role name alone.
Instructions
Follow the five steps in order. Each step's full code is in
references/implementation.md under the matching
heading — the skeletons below show the essential call surface.
Step 1: List admins and roles
Enumerate every admin and team to map real identities to permissions.
const client = new IntercomClient({ token: process.env.INTERCOM_ACCESS_TOKEN! });
const adminList = await client.admins.list();
// admin.type is "admin" or "team" — teams are used for routing in Step 4
Step 2: OAuth scope-based access control
For public apps, request the minimal scopes required, build the authorization
URL with a CSRF state, and exchange the returned code for a per-workspace token.
const authUrl = getAuthUrl(crypto.randomUUID()); // redirect the user here
const { token } = await exchangeCode(code); // on callback
Store one token per workspace (WorkspaceAuth
'Create a minimal working Intercom example with contacts, conversations,.
ReadWriteEdit
Intercom Hello World
Overview
Minimal working examples covering the Intercom core data model: contacts (users and leads), conversations, messages, and tags. This skill gives you the first end-to-end round trip against the Intercom REST API — create a contact, search it, message it, open a conversation, and tag it — so you can confirm your credentials work and internalize how the entities relate before building anything real.
Prerequisites
Before running any snippet below, make sure the following are in place. Each is verified once during the intercom-install-auth setup step:
- Completed the
intercom-install-auth setup (installs the SDK and stores your token).
- The
intercom-client npm package installed in your project (npm install intercom-client).
- A valid Intercom access token exported as
INTERCOMACCESSTOKEN in your environment. The SDK reads this token to authenticate every request; there is no separate login call.
Instructions
The workflow is five short steps against the core data model. The first —
creating a contact — is shown in full here so you can run immediately. Steps 2
through 5 (search, message, conversation, tag) follow the identical
client..(...) shape and live in the walkthrough reference.
Step 1: Create a Contact
Contacts are the core entity. They have a role of either user (identified) or lead (anonymous).
import { IntercomClient } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
// Create a user contact
const user = await client.contacts.create({
role: "user",
externalId: "user-12345",
email: "jane@example.com",
name: "Jane Smith",
});
console.log(`Created contact: ${user.id} (${user.role})`);
Remaining steps
Continue in the full walkthrough, which covers,
with complete code and response shapes:
- Step 2 — Search for Contacts (
client.contacts.search)
- Step 3 — Send a Message (
client.messages.create, admin → contact)
- Step 4 — Create a Conversation (
client.conversations.create)
- Step 5 — Tag a Contact (
client.tags.create + client.contacts.tag)
The walkthrough also carries the full Core Data Model reference table
(Contact, Conversation, Message, Tag, Company, Admin and their key fields).
Output
Running the snippets produces:
- A created contact object —
id, role, e
Execute Intercom incident response procedures with triage, mitigation, and postmortem.
Bash(curl:*)Bash(kubectl:*)
Intercom Incident Runbook
Overview
Rapid incident response procedures for Intercom integration failures. The runbook
takes you from alert to resolution in four phases — triage, decision, mitigation,
and postmortem — with HTTP-status-code-driven branching so you always know whether
the fault is yours or Intercom's. High-level workflow lives here; the full
copy-paste scripts and templates live in references/.
Prerequisites
INTERCOMACCESSTOKEN exported in your shell (a workspace admin token).
curl and jq installed for API + status-page probing.
kubectl access to the deployment running your Intercom integration (for restarts).
- Access to your secret manager (e.g. AWS Secrets Manager) to rotate a compromised token.
- Developer Hub access for the Intercom app, or a path to escalate to a workspace admin.
Severity Levels
| Level |
Definition |
Response Time |
Example |
| P1 |
All Intercom API calls failing |
< 15 min |
401 auth failures, API unreachable |
| P2 |
Degraded service |
< 1 hour |
High latency, rate limited (429) |
| P3 |
Partial impact |
< 4 hours |
Webhook delays, search timeouts |
| P4 |
No user impact |
Next business day |
Monitoring gaps, stale cache |
Instructions
Work the phases in order. Each phase links to the full reference when you need depth.
- Assign severity. Match the symptom to the table above; this sets your clock
and who you page.
- Triage — is it you or Intercom? Run the first probe to confirm reachability:
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
https://api.intercom.io/me
Then check status.intercom.com for a platform incident and read the rate-limit
headers. The full 5-step diagnostic script and the branch-by-branch decision tree
are in references/triage.md.
- Decide. If Intercom reports an incident, it is their problem — enable graceful
degradation and monitor. If not, it is your integration; branch on the status code:
401 → rotate token, 403 → add OAuth scope, 429 → queue/backoff, 5xx → retry with backoff.
- Mitigate by error type. Apply the matching remediation — token rotation for 401,
volume reduction for 429, cached-data fallback for 5xx. Full commands (including the
aws secretsmanager rotation and the
Install and configure Intercom API authentication with access tokens or OAuth.
WriteBash(npm:*)
Intercom Install & Auth
Overview
Set up the official intercom-client TypeScript SDK and configure authentication via access tokens (private apps) or OAuth (public apps). This skill installs the SDK with a Bash npm command, uses Write to create the client config and .env, and verifies the connection.
Prerequisites
- Node.js 18+
- npm, pnpm, or yarn
- Intercom workspace with Developer Hub access
- Access token from Configure > Authentication in your app settings
Instructions
Step 1: Install the SDK
npm install intercom-client
The package exports IntercomClient and all TypeScript types under the Intercom namespace.
Step 2: Configure Access Token Authentication
Access tokens authenticate private apps that access your own Intercom workspace. Use Write to create the client module and a .env holding the token (add .env to .gitignore):
import { IntercomClient } from "intercom-client";
const client = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
See examples.md for the full .env setup and secure-storage steps.
Step 3: Verify Connection
List admins to confirm the token authenticates end-to-end:
const admins = await client.admins.list();
console.log("Connected! Admins:", admins.admins.length);
The complete verification function (with error handling and expected output) is in examples.md.
Step 4: OAuth Setup (Public Apps)
For a public app that accesses other workspaces, run the OAuth authorization → token-exchange flow, then initialize the client with the returned token:
const client = new IntercomClient({ token: oauthToken });
Full OAuth exchange, API-version pinning, and the scope matrix are in oauth.md.
Output
Running this skill produces:
intercom-client installed in node_modules and added to package.json.
- A configured
IntercomClient module authenticated via access token or OAuth.
- A
.env holding INTERCOMACCESSTOKEN (private app) or INTERCOMCLIENTID / INTERCOMCLIENTSECRET (OAuth), with .env gitignored.
- A verified connection —
client.admins.list() returns your workspace admins, confirming the token and API version (2.11, applied automatically by the SDK) are correct.
Error Handling
Common authe
Configure Intercom local development with testing, mocking, and hot reload.
ReadWriteEditBash(npm:*)Bash(npx:*)
Intercom Local Dev Loop
Overview
Set up a fast local development workflow for Intercom integrations with proper
test isolation, mocking strategies, and webhook tunneling. The loop has two
lanes: a mocked unit lane that runs offline with no token, and an integration
lane that talks to a real dev workspace and is skipped automatically when no
token is present.
Prerequisites
- Completed
intercom-install-auth setup
- Node.js 18+ with npm/pnpm
- A test/development Intercom workspace (separate from production)
Authentication
The client authenticates with a single Intercom bearer access token, issued per
workspace by the intercom-install-auth step. Read it from
process.env.INTERCOMACCESSTOKEN (loaded from git-ignored .env.development);
never hardcode it. The mocked unit lane needs no token at all — pointing the loop
at a different dev workspace is only a matter of swapping the .env.development
value.
Instructions
Work through these steps to stand up the loop. The full, copy-paste-ready code
for every step lives in the implementation walkthrough.
- Scaffold the project structure — an
src/intercom/ module (singleton
client.ts, plus contacts.ts / conversations.ts / types.ts), a tests/
tree with a mocks/ factory, and three env files (.env.example committed,
.env.development and .env.test git-ignored). Use Write to create each
file. See implementation.md.
- Configure environments — commit
.env.example as the template and keep
real tokens in the git-ignored .env.development. See
implementation.md.
- Write an environment-aware client singleton that reads the token, throws a
clear error when it is missing, and exposes a resetClient() for tests. The
skeleton:
// src/intercom/client.ts
import { IntercomClient } from "intercom-client";
let instance: IntercomClient | null = null;
export function getClient(): IntercomClient {
if (!instance) {
const token = process.env.INTERCOM_ACCESS_TOKEN;
if (!token) {
throw new Error(
"INTERCOM_ACCESS_TOKEN not set. Copy .env.example to .env.development"
);
}
instance = new IntercomClient({ token });
}
return instance;
}
export function resetClient(): void {
instance = null;
Use when migrating from Zendesk/Freshdesk/HelpScout to Intercom, bulk-importing contacts, or re-platforming to Intercom with the contacts, conversations, and articles APIs.
ReadWriteEditBash(npm:*)Bash(node:*)
Intercom Migration Deep Dive
Overview
Comprehensive guide for migrating to Intercom from other platforms (Zendesk,
Freshdesk, HelpScout) or bulk-importing data. Covers contact import, company
import, tags, Help Center articles, orchestration, and post-migration
validation. The full runnable TypeScript for every phase lives in
references/implementation.md; this file carries
the workflow and the first-phase skeleton so you can follow it end to end, then
drill into the reference for depth.
Prerequisites
- Intercom workspace with an access token exported as
INTERCOMACCESSTOKEN
- Source system data exported (CSV or API access)
- The
intercom-client SDK installed (npm install intercom-client)
- Feature flag infrastructure for gradual cutover
- Rollback strategy tested
Authentication
All scripts read the workspace access token from the environment — never
hard-code it. Create the token in the Intercom Developer Hub (Settings →
Developers → your app → Authentication), then:
export INTERCOM_ACCESS_TOKEN="your-workspace-access-token"
import { IntercomClient, IntercomError } from "intercom-client";
const client = new IntercomClient({ token: process.env.INTERCOM_ACCESS_TOKEN! });
Migration Types
| Type |
Complexity |
Duration |
Risk |
| Contact import |
Low |
Hours |
Low |
| Zendesk/Freshdesk migration |
Medium |
1-2 weeks |
Medium |
| Full re-platform (with history) |
High |
2-4 weeks |
High |
| Help Center migration |
Medium |
Days |
Low |
Instructions
Run the phases in dependency order. Each phase is a standalone function in
references/implementation.md; the orchestrator in
Step 5 chains them.
- Contacts (Step 1) — idempotent: search by
external_id/email, then
update or create. Stamp migratedfrom + migrationdate custom attributes
so rollback can find migrated records. Skeleton below.
- Companies (Step 2) — import before attaching contacts; contacts reference
companies.
- Tags (Step 3) — create each tag, apply to its contacts, skip missing
(404) contacts instead of aborting.
- Articles (Step 4) — group into Help Center collections by category,
creating each collection once.
'Configure Intercom across development, staging, and production workspaces.
ReadWriteEditBash(aws:*)Bash(gcloud:*)Bash(vault:*)
Intercom Multi-Environment Setup
Overview
Configure separate Intercom workspaces for development, staging, and production with environment-specific access tokens, webhook URLs, and safety guards. This skill establishes a single config loader, an environment-aware client factory, per-platform secret storage, and production guards so the same codebase behaves correctly in every environment.
The full step-by-step code lives in references/implementation.md; this file carries the workflow and the Step 1 skeleton so you can follow it end to end, then drill into the reference for depth.
Prerequisites
- Separate Intercom workspaces (or at minimum, separate apps in Developer Hub)
- Secret management solution (Vault, AWS Secrets Manager, GCP Secret Manager)
- CI/CD pipeline with environment variable support
Environment Strategy
| Environment |
Workspace |
Token Type |
Data |
Webhooks |
| Development |
Dev/sandbox workspace |
Dev access token |
Test data |
localhost via ngrok |
| Staging |
Staging workspace |
Staging token |
Seed data |
staging.example.com |
| Production |
Production workspace |
Production token |
Real data |
api.example.com |
Instructions
Work through six steps. Read the Step 1 skeleton below to see the shape of the config, then open references/implementation.md for the complete code of every step.
- Environment Configuration — a single
loadConfig() reads NODE_ENV and merges shared secrets with per-environment defaults (debug, cache TTL, rate-limit concurrency). Skeleton below.
- Environment-Aware Client Factory — a lazily-initialised
getClient() that throws a clear, environment-named error when the token is missing.
- Secret Management by Platform — store tokens in git-ignored
.env. files locally and in GitHub Actions, AWS Secrets Manager, GCP Secret Manager, or HashiCorp Vault in CI/prod.
- Production Safety Guards — an
EnvironmentGuard with requireProduction() / preventProduction() so destructive jobs can never fire in the wrong workspace.
- Webhook URL per Environment — map
NODE_ENV to the correct public webhook URL so no code changes between deploys.
- Environment Validation on Startup — probe the workspace on boot; fail fast in production, warn (but continue) elsewhere.
Step 1 skeleton — the config loader every other step depends on:
Use when you need production monitoring for an Intercom integration — instrumenting API calls with metrics and traces, standing up dashboards, or wiring alerts for error rate, latency, and rate-limit health.
ReadWriteEdit
Intercom Observability
Overview
Comprehensive observability for Intercom integrations covering Prometheus metrics,
OpenTelemetry traces, structured logging, and alert rules for error rates, latency,
and rate-limit usage. Read this page for the workflow and shape of each layer, then
drill into references/implementation.md for the full,
copy-pasteable code and references/examples.md for
end-to-end worked scenarios.
Prerequisites
- Prometheus or compatible metrics backend
- OpenTelemetry SDK (optional, for tracing)
- Pino or similar structured logger
- Grafana or alerting system
Instructions
Build the six observability layers in order. Each step below is the summary and the
essential skeleton — the complete implementation for every step lives in
references/implementation.md.
Step 1: Prometheus metrics
Define five instruments on a shared Registry: a request counter, a duration
histogram, an error counter, a rate-limit gauge, and a webhook counter. Label by
endpoint/method/status (never by unbounded IDs — see Error Handling).
import { Registry, Counter, Histogram, Gauge } from "prom-client";
const registry = new Registry();
const intercomRequests = new Counter({
name: "intercom_api_requests_total",
help: "Total Intercom API requests",
labelNames: ["endpoint", "method", "status"] as const,
registers: [registry],
});
// + duration Histogram, error Counter, rate-limit Gauge, webhook Counter
Full metric set → references/implementation.md, Step 1.
Step 2: Instrumented client wrapper
Wrap IntercomClient in a Proxy that times every service method, increments the
success/error counters, records error/status codes on IntercomError, and zeros the
rate-limit gauge on a 429 — so instrumentation is automatic for all endpoints.
Full proxy → references/implementation.md, Step 2.
Step 3: Structured logging
Configure Pino with a contact serializer that emits only id/role and never
logs email, name, or phone. Add logIntercomOp and logWebhook helpers for
consistent operation/webhook log lines.
Full logger → references/implementation.md, Step 3.
Step 4: OpenTelemetry tracing
Wrap calls in tracedIntercomCall, which opens a per-operat
Optimize Intercom API performance with caching, search optimization, and pagination.
ReadWriteEdit
Intercom Performance Tuning
Overview
Optimize Intercom API performance through response caching, efficient search queries, cursor-based pagination, connection pooling, and request batching.
Prerequisites
intercom-client SDK installed
- Understanding of Intercom data model
- Redis or in-memory cache available (optional)
Authentication
All requests authenticate with an Intercom access token passed as a bearer token. Store it as INTERCOMACCESSTOKEN in the environment and let the SDK read it — never hardcode it:
const client = new IntercomClient({ token: process.env.INTERCOM_ACCESS_TOKEN! });
For raw fetch calls, send Authorization: Bearer ${token}.
Intercom API Latency Baselines
| Operation |
Typical P50 |
Typical P95 |
Notes |
GET /me (health check) |
50ms |
150ms |
Lightest endpoint |
GET /contacts/:id |
80ms |
200ms |
Single lookup |
POST /contacts/search |
120ms |
400ms |
Depends on query complexity |
GET /conversations/:id |
100ms |
300ms |
Heavier with parts (up to 500) |
POST /contacts (create) |
150ms |
400ms |
Write operation |
GET /contacts (list) |
100ms |
350ms |
Paginated, 50 per page |
POST /messages |
200ms |
500ms |
Triggers delivery pipeline |
Instructions
Apply these six techniques in order of impact. Each has a complete, copy-pasteable implementation in references/implementation.md; the summaries and the caching skeleton below are enough to follow the workflow at a high level.
- Response caching — wrap contact/conversation reads in an
LRUCache (read-through), and invalidate on update or via webhook so cached data never goes stale. This is the single biggest win for read-heavy integrations.
- Efficient search queries — push predicates into the
AND-combined query and request only the per_page you need (max 150), rather than fetching broadly and filtering client-side.
- Optimized pagination — stream large result sets with an async generator over cursor pagination (
startingAfter) to keep memory flat, and process in fixed-size batches.
- Connection pooling — reuse TCP connections with an
https.Agent (keepAlive: true) so you pay the TLS handshake cost
'Execute Intercom production readiness checklist and rollback procedures.
ReadBash(curl:*)Grep
Intercom Production Checklist
Overview
Complete checklist for deploying Intercom integrations to production, covering
authentication, error handling, rate limits, webhooks, and monitoring. Work the
pre-deployment checklist below section by section, run the pre-flight script as
the go-live gate, and keep the rollback procedure ready before you launch.
Prerequisites
- A production Intercom workspace with an access token issued from the Developer Hub.
$INTERCOMACCESSTOKEN exported in the environment where you run the checks.
curl and jq available for the pre-flight and status probes.
- The integration deployed behind a feature flag so it can be disabled without a redeploy.
- (Optional)
$WEBHOOK_URL set if the integration receives Intercom webhooks.
Instructions
Work through the checklist in order. Each group gates a distinct failure class —
do not skip a group because "it probably works."
Authentication and secrets
- [ ] Production access token stored in secret manager (not env files)
- [ ] Token has minimal required OAuth scopes
- [ ] Token rotation procedure documented and tested
- [ ] Separate tokens for dev/staging/production workspaces
- [ ] No hardcoded tokens in source code (verified with
grep -r "dG9r" .)
API integration quality
- [ ] All API calls wrapped in error handling (
try/catch with IntercomError)
- [ ] 429 rate limit retry with exponential backoff implemented
- [ ] 5xx server error retry implemented
- [ ] Request timeouts configured (recommended: 30s)
- [ ] Pagination handles cursor-based iteration correctly
- [ ] Contact search uses compound queries efficiently
Webhook endpoints
- [ ] Webhook URL uses HTTPS (Intercom requires it)
- [ ]
X-Hub-Signature verification implemented (HMAC-SHA1)
- [ ] Webhook handler responds within 5 seconds (Intercom timeout)
- [ ] Idempotency: duplicate webhooks handled gracefully
- [ ] Failed webhook retry handled (Intercom retries once after 1 min)
Data handling
- [ ] PII redacted from logs (emails, names, phone numbers)
- [ ] Contact data cached with appropriate TTL
- [ ] GDPR deletion handler implemented for contact data
- [ ] Custom attributes validated before sending to API
Monitoring and alerting
- [ ] Health check endpoint includes Intercom connectivity test
- [ ] Error rate alerting configured (threshold: 5% over 5 min)
- [ ] Rate limit usage tracked (alert at 80% of limit)
- [ ] Latency monitoring (alert if P95 > 2 seconds)
- [ ] Intercom status page monitored (https://status.intercom.com)
'Handle Intercom API rate limits with backoff, queuing, and header monitoring.
ReadWriteEdit
Intercom Rate Limits
Overview
Intercom enforces rate limits per app and per workspace. Handle 429 errors
gracefully with exponential backoff, queue-based throttling, and proactive
header monitoring. This skill gives you five composable defenses — a retry
wrapper, a live monitor, a request queue, request batching, and metrics — so a
high-volume integration stays under the ceiling instead of spraying 429s.
The full, copy-paste TypeScript for all five lives in
references/implementation.md; this page carries
the limits, the header contract, and a lean skeleton so you can wire it up from
here and drill in for depth.
Rate Limit Tiers
| Scope |
Limit |
Notes |
| Private app |
10,000 req/min |
Per app |
| Public app (OAuth) |
10,000 req/min |
Per app |
| Workspace total |
25,000 req/min |
Across all apps |
| Search endpoints |
1,000 req/min |
/contacts/search, /conversations/search |
| Scroll endpoints |
100 req/min |
Bulk data export |
Rate Limit Headers
Every response includes these headers — read them to throttle proactively:
X-RateLimit-Limit: <max requests per window>
X-RateLimit-Remaining: <remaining requests>
X-RateLimit-Reset: <unix timestamp when window resets>
Prerequisites
- An Intercom access token in
INTERCOMACCESSTOKEN (Developer Hub > Your App
> Authentication) — all requests below send it as Authorization: Bearer.
- The official SDK:
npm install intercom-client.
- For queue-based throttling:
npm install p-queue.
- Read an existing client wrapper before editing so you extend it rather
than duplicate it.
Instructions
Apply the defenses in order — each builds on the previous one. Use Write to
create a new intercom-rate-limit.ts module, or Edit to fold these into an
existing client wrapper.
- Wrap every call in header-aware retry. On
429, wait until
X-RateLimit-Reset; on 5xx, exponential backoff with jitter. Skeleton:
async function withRateLimitRetry<T>(op: () => Promise<T>): Promise<T> {
// On 429: delay = (X-RateLimit-Reset * 1000) - Date.now() + 1000
// On 5xx: delay = baseDelay * 2^attempt + jitter, capped at maxDelayMs
}
- Add a proactive monitor. Feed response headers into a monitor and c
'Implement Intercom reference architecture with layered project structure.
ReadGrep
Intercom Reference Architecture
Overview
A production-ready reference architecture for Intercom integrations built on
four layers — API/webhook, service, Intercom client, and infrastructure — with
type-safe SDK usage, webhook processing, contact sync, and Help Center
management. Use it to scaffold a new integration or to review an existing one
against a known-good structure.
The layers (top to bottom): the API / Webhook layer (Express routes, webhook
endpoints) calls into the service layer (contacts, conversations, articles —
business logic and orchestration), which calls the Intercom client layer (a
singleton intercom-client SDK wrapper with typed errors, caching, and rate
limit handling), all resting on infrastructure (Redis cache, job queue,
monitoring). Keeping dependencies flowing strictly downward is what prevents the
circular imports and test-isolation problems listed under Error Handling.
Prerequisites
- Node.js project with TypeScript and the
intercom-client npm package
installed.
- An Intercom access token — the SDK authenticates every request with a
Bearer token read from the INTERCOMACCESSTOKEN environment variable (see
Step 1). Create one under Intercom → Developer Hub → your app →
Authentication. Never commit it; load it from the environment.
- For webhook verification, your app's client secret to validate the
X-Hub-Signature header on inbound webhook POSTs.
- Redis (optional) if you enable the caching layer.
Instructions
Use Read/Grep to inspect the current project layout, then build each layer
in order — the client layer is the dependency root for every service.
- Client layer (
src/intercom/client.ts) — a lazy singleton
getClient() that reads INTERCOMACCESSTOKEN once, plus an
IntercomServiceError that wraps raw SDK errors into a typed, retry-aware
shape. Skeleton:
let instance: IntercomClient | null = null;
export function getClient(): IntercomClient {
if (!instance) {
const token = process.env.INTERCOM_ACCESS_TOKEN;
if (!token) throw new Error("INTERCOM_ACCESS_TOKEN required");
instance = new IntercomClient({ token });
}
return instance;
}
- Contacts service (
src/services/contacts.service.ts) —
findOrCreate (search-before-create to avoid 409s), syncFromCRM,
mergeLead, and a searchAll
'Apply production-ready intercom-client SDK patterns for TypeScript.
ReadWriteEdit
Intercom SDK Patterns
Overview
Production-ready patterns for the intercom-client TypeScript SDK covering
client initialization, cursor-based pagination, error handling, retry with
backoff, compound search, and multi-tenant client factories. Use this skill to
Read existing Intercom code, then Write or Edit it to match these patterns —
type-safe singletons, memory-efficient pagination, and resilient error handling.
The SKILL.md body carries the essential skeletons (client wrapper, pagination,
error-handling shape). Deep implementations and worked examples live in
references/ so you can drill in only when you need them:
retry/backoff, multi-tenant factory, search-operator table.
combined retry + safe-call.
Prerequisites
intercom-client package installed (npm install intercom-client).
- TypeScript 5.0+ project with
strict mode enabled.
- Familiarity with
async/await and async generators.
- An Intercom access token available at runtime (see Authentication below).
Authentication
The SDK authenticates with a workspace access token passed to the
IntercomClient constructor. Store it in the INTERCOMACCESSTOKEN environment
variable — never hardcode it. Generate the token from Intercom's Developer Hub
(Settings → Authentication). For multi-workspace apps, each workspace has its own
token; see the multi-tenant factory in
references/implementation.md.
Instructions
Step 1: Type-Safe Client Wrapper
Create one lazily-initialized singleton client plus thin, typed helpers. This
keeps a single connection pool and gives every call-site full SDK types.
// src/intercom/client.ts
import { IntercomClient } from "intercom-client";
import { Intercom } from "intercom-client";
let instance: IntercomClient | null = null;
export function getClient(): IntercomClient {
if (!instance) {
instance = new IntercomClient({
token: process.env.INTERCOM_ACCESS_TOKEN!,
});
}
return instance;
}
// Type-safe contact creation helper
export async function createContact(
params: Intercom.CreateContactRequest
): Promise<Intercom.Contact> {
return getClient().contacts.create(params);
}
Step 2: Cursor-Based Pagination
Intercom lists are cursor-paginated — starting_after points to the next page.
Prefer the SDK's built-in async iteration, which manages the c
'Apply Intercom security best practices for tokens, webhook verification,.
ReadWriteGrep
Intercom Security Basics
Overview
Security best practices for Intercom access tokens, webhook signature
verification, Identity Verification (HMAC), and least-privilege OAuth scopes.
The full code for each control lives in references/ so this file stays a fast,
high-level checklist you can follow end-to-end, then drill into for depth:
identity, rotation, and scope code.
Prerequisites
- Intercom access token or OAuth credentials
- Understanding of HMAC cryptographic signatures
- Access to Intercom Developer Hub
Instructions
Step 1: Secure Token Storage
Store every secret in .env (or a secret manager) and never commit it.
# .env (NEVER commit to git)
INTERCOM_ACCESS_TOKEN=dG9rOmFiY2RlZmdoaQ==
INTERCOM_WEBHOOK_SECRET=your-webhook-signing-secret
INTERCOM_IDENTITY_SECRET=your-identity-verification-secret
# .gitignore (mandatory entries)
.env
.env.local
.env.*.local
Then scan history for anything already leaked — use Grep (or the shell) to
search committed content for token markers:
git log --all -p | grep -i "INTERCOM_ACCESS_TOKEN\|dG9r" | head -5
# If found: rotate the token immediately, then use git-filter-repo to remove it.
Step 2: Webhook Signature Verification (X-Hub-Signature)
Intercom signs webhook notifications with HMAC-SHA1 using X-Hub-Signature.
Verify it on every incoming webhook against the raw request body, using a
timing-safe comparison, and reject mismatches with 401:
const expectedSignature = "sha1=" + crypto
.createHmac("sha1", secret)
.update(payload) // payload = raw Buffer, not parsed JSON
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
Full Express handler: implementation.md — Webhook Signature Verification.
Step 3: Identity Verification (User Hash)
Identity Verification blocks impersonation by requiring an HMAC-SHA256 of the
user's identifier, generated server-side only:
crypto.createHmac("sha256", process.env.INTERCOM_IDENTITY_SECRET!)
.update(userId)
.digest("hex");
Return this userhash alongside appid and user_id for Messenger boot. Full
code: implementation.md — Identity Verification
Upgrade the intercom-client SDK across major versions and handle Intercom API version changes safely.
ReadWriteEditBash(npm:*)Bash(git:*)
Intercom Upgrade & Migration
Overview
Upgrade the intercom-client npm package and handle Intercom API version
changes without breaking production traffic. The v6 TypeScript rewrite changed
the API surface — most notably unifying users/leads into a single contacts
API — so this skill drives a branch-based, type-checked upgrade that surfaces
every breaking change through the compiler and test suite before merge.
Deep material lives in references/ so this file stays scannable:
operation with before/after code, API-version pinning, the upgrade procedure,
type-import changes, and the method cheat sheet.
detection through a committed upgrade branch.
Prerequisites
- A project with
intercom-client already installed (npm list intercom-client
shows the current version).
- Git available for branch-based upgrades and reviewable diffs.
- A working test suite, ideally including an integration suite that can run
against a dev Intercom workspace.
- TypeScript (
tsc) configured if migrating to v6+, since the compiler is the
primary breaking-change detector.
Authentication
Intercom API calls authenticate with a workspace access token passed as a Bearer
token. Read it from the INTERCOMACCESSTOKEN environment variable — never
hardcode it. Version-detection curls and the integration test step both consume
this variable:
export INTERCOM_ACCESS_TOKEN="<workspace-access-token>" # from Intercom > Developer Hub
Use a separate dev-workspace token ($DEV_TOKEN) for the integration test step
so the upgrade is validated without touching production data.
Instructions
Follow the workflow at a high level here; drill into
the migration guide for the exact code diffs.
Step 1: Check current versions
Read (with the Read tool or npm list) the installed version, the latest
published version, and the live API version to size the upgrade:
npm list intercom-client # installed SDK version
npm view intercom-client version # latest available
curl -s -D - -o /dev/null \
-H "Authorization: Bearer $INTERCOM_ACCESS_TOKEN" \
https://api.intercom.io/me 2>/dev/null | grep -i intercom-version
If the installed major is < 6 and the target is ≥ 6, expect the TypeScript-
'Implement Intercom webhook handling and data event tracking.
ReadWriteEditBash(curl:*)
Intercom Webhooks & Events
Overview
Handle incoming Intercom webhooks (notifications) with signature verification and implement outbound data event tracking via the Events API. Incoming webhooks push conversation and contact changes to your endpoint; outbound data events push custom activity into Intercom for segmentation and messaging.
The full, copy-ready code lives in references/; this file walks the workflow at a high level so you can follow it start to finish, then drill in for depth.
Prerequisites
- HTTPS endpoint accessible from internet
- Webhook secret from Intercom Developer Hub
- Access token from Intercom Developer Hub (for outbound data events)
intercom-client SDK installed
- Redis or database for idempotency (recommended)
Authentication
Two distinct credentials, both issued from the Intercom Developer Hub and read from environment variables — never hard-code them:
- Incoming webhooks are verified with
INTERCOMWEBHOOKSECRET. Intercom signs every delivery with HMAC-SHA1 in the X-Hub-Signature header; you recompute the digest over the raw request body and compare with crypto.timingSafeEqual. Reject any request that fails or is missing the header.
- Outbound data events authenticate with a bearer
INTERCOMACCESSTOKEN passed to IntercomClient.
Instructions
Read the relevant reference file, then use Write/Edit to scaffold the handler into the target project.
- Build the signed endpoint. Create an Express route that captures the raw body (
express.raw), verifies the X-Hub-Signature HMAC-SHA1 digest against INTERCOMWEBHOOKSECRET, and returns 200 within 5 seconds — Intercom treats a slower response as a failure. Respond first, process after. See incoming webhooks walkthrough Step 1.
- Model the payload. Every delivery is a
notification_event envelope carrying topic, id, and data.item (the changed resource). Type it so the router is safe. See incoming webhooks walkthrough Step 2.
- Route by topic. Dispatch on
notification.topic through a handler map; log and no-op unknown topics rather than throwing. Pick topics from the topics reference. See incoming webhooks walkthrough Step 3.
- Add idempotency. Intercom retries a failed delivery once after ~1 minute. Guard each
notification.id with a Redis SET NX lock s
Ready to use intercom-pack?
|