intercom-reference-architecture

'Implement Intercom reference architecture with layered project structure.

Allowed Tools

ReadGrep

Provided by Plugin

intercom-pack

Claude Code skill pack for Intercom (24 skills)

saas packs v1.6.0
View Plugin

Installation

This skill is included in the intercom-pack plugin:

/plugin install intercom-pack@claude-code-plugins-plus

Click to copy

Instructions

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.

  1. 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;
   }
  1. Contacts service (src/services/contacts.service.ts) —

findOrCreate (search-before-create to avoid 409s), syncFromCRM,

mergeLead, and a searchAll async generator for cursor pagination.

  1. Conversations service (src/services/conversations.service.ts) —

replyAsAdmin, addNote, closeWithMessage, and a scoped open-queue

search.

  1. Articles service (src/services/articles.service.ts) — Help Center

article create/list, defaulting new articles to draft.

  1. Wire the data flow — Intercom pushes events to your webhook router; the

service layer makes API calls back and persists to your database + cache.

The full project tree, every service method, and the layer/data-flow diagrams

are in the full implementation walkthrough; the

complete directory layout is in

project-structure.md.

Output

Applying this skill produces a layered Intercom integration:

  • A src/intercom/ client layer (singleton SDK wrapper + typed errors).
  • A src/services/ layer with contacts, conversations, and articles services.
  • src/webhooks/, src/sync/, src/api/, and src/cache/ directories wired

to the layers above.

  • Per-environment config/ files and a tests/ tree with unit + integration

suites.

When used to review an existing project, the output is a gap report: which

layers exist, which are missing, and where dependency direction is violated.

Error Handling

Issue Cause Solution
Circular dependencies Service A imports B imports A Use dependency injection
Client initialization race Async token fetch Lazy singleton pattern
Cache inconsistency Stale data after update Webhook-driven invalidation
Test isolation Shared SDK state resetClient() in beforeEach
401 Unauthorized Missing/invalid INTERCOMACCESSTOKEN Verify the env var is loaded before getClient()
429 Too Many Requests Rate limit exceeded Retry with backoff — IntercomServiceError.retryable is true here

Examples

Once the client and service layers exist, wiring them together is a few lines —

sync a CRM user, reply to and close a conversation, page through contacts, or

publish an article:


const contacts = new ContactsService();
const contact = await contacts.syncFromCRM({
  id: "crm_8842", email: "ada@example.com", name: "Ada Lovelace",
  plan: "enterprise", company: "Analytical Engines Ltd",
});

See examples.md for the full set of runnable usage

snippets (conversation reply/close, paginated search, Help Center publish).

Resources

Next Steps

For multi-environment configuration and deployment, see the

intercom-multi-env-setup skill, which extends the config/ layer described

above into per-environment credential and rate-limit management.

Ready to use intercom-pack?