Intercom

Lightweight, dependency-free, in-memory fake of the Intercom REST API for testing code that uses the intercom-client Node SDK (or the REST API directly).

Default port: 4780

Quick start

import { IntercomServer } from "./services/intercom/src/server.js";

const server = new IntercomServer(4780);
await server.start();
// ... run your app/tests ...
await server.stop();

Point a client at it:

const base = "http://127.0.0.1:4780";
const res = await fetch(`${base}/contacts`, {
  method: "POST",
  headers: {
    Authorization: "Bearer pat-parlel",
    "Intercom-Version": "2.11",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ email: "a@parlel.dev", name: "Ada" }),
});
// => { type: "contact", id, email, ... }

Access via MCP / preview URL

Plain HTTP at http://127.0.0.1:4780, reachable through the parlel MCP/preview proxy under the slug intercom. The Intercom-Version request header is honoured and echoed on the response.

Implemented operations

All API routes require Authorization: Bearer <token> (any non-empty bearer works). State is in-memory and ephemeral.

Object shape: { type: "contact", id, ... }. List shape: { type: "list", data: [...], pages: {...}, total_count }.

Contacts — /contacts

Conversations — /conversations

Messages — /messages

Service & inspection operations (parlel extensions)

Surface coverage

This emulator faithfully replicates the API surface most application code and agents exercise. Anything below the supported lines is either an intentional design choice for a fast, zero-cost local emulator (✓ By design) or a candidate for a future release (⟳ Roadmap) — never a silent inaccuracy.

Legend: ✅ fully supported · ◐ accepted (stored, not strictly enforced) · ✓ by design · ⟳ on the roadmap.

FeatureStatus
Contacts CRUD + search✅ Supported
Conversations create/list/get/update✅ Supported
Messages create✅ Supported
Intercom-Version header echo✅ Supported
Companies / tags / segments / data attributes⟳ Roadmap
Reply / attach / conversation parts⟳ Roadmap
Full search operator grammar (AND/OR trees)◐ Single-clause subset
Token validity / workspace scoping✓ By design — Any non-empty credential is accepted — no real secrets needed
Rate limiting (429)✓ By design — Never throttles — local tests run at full speed, zero cost

Error codes & shapes

Errors use the Intercom envelope { type: "error.list", request_id, errors: [{ code, message }] }.

StatuscodeWhen
400bad_request / parameter_invalidmalformed JSON / missing from
401unauthorizedno Authorization: Bearer header
404not_foundunknown id / endpoint
405method_not_allowedmethod not allowed for the path

Manifest

See services/intercom/manifest.json: name intercom, port 4780, protocol http, healthcheck /health, startup ≈ 100ms, env INTERCOM_ACCESS_TOKEN, INTERCOM_BASE_URL.

<!-- parlel:testenv:start -->

Configuration — test.env

Copy these into your test.env (used by the bridge sidecar flow). Tokens are Parlel's seeded test credentials — any non-empty value is accepted by the emulator, so you rarely need to change them. Swap in real credentials only when pointing at the live service in prod.env.

INTERCOM_ACCESS_TOKEN=pat-parlel
INTERCOM_BASE_URL=http://parlel-bridge:4780
<!-- parlel:testenv:end -->