Migrating off Intercom — phase by phase.
Intercom migrations have three quirks worth knowing: the conversations API uses cursor pagination and is rate-limited at ~1,000 requests/min, the Messenger widget identifies users via a signed `user_hash` you'll need to mint from your own backend, and Help Center articles live on an intercom.help subdomain whose URLs you'll want to mirror (or 301-redirect) to preserve SEO equity.
The phases, tuned to Intercom
Each phase below is the Intercom-specific version of our standard playbook. Same shape every engagement, different specifics per SaaS.
Workflow & macro audit
1-2 weeksWe inventory every Trigger, Workflow, Macro, Series and Custom Bot before touching the data. Most teams find that 30+ rules accumulated over years collapse to 8-10 once you remove duplicates and dead branches.
✓Export and read every Workflow + Custom Bot config (the JSON isn't reimportable but it's a good starting reference)✓List every Macro and tag the ones that haven't fired in 90 days✓Map the Inbox routing rules to a state machine on paper✓Identify which Fin AI Topics are doing real work vs. acting as fallbacks✓List the Help Center articles by URL path so we can plan 301sYou walk away withA Workflow & Macro Inventory listing what we'll port, what we'll drop, and the URL list for the Help Center redirect map.
Schema + Postgres model design
1 weekConversations, contacts, companies, tags, and articles get a properly-normalised Postgres model. Intercom IDs get preserved as columns so any external system pointing at them keeps working.
✓Design tables: conversations, conversation_parts, contacts, companies, tags, articles, collections✓Preserve `intercom_id` on every record (indexed) for backwards compatibility✓Plan a GIN index on conversation parts for full-text search✓Design the article schema as MDX-on-disk + a search index (Typesense or Postgres tsvector)✓Sign DPA + sub-processor list with your teamYou walk away withSchema migrations checked into git + a published sub-processor list.
Extract via REST API
1-2 weeksWe pull conversations, contacts, companies, tags and Help Center content via the Intercom REST API. The conversations endpoint is the slow one — cursor pagination plus the rate limit means it's the long pole.
✓Authenticate via Personal Access Token (or OAuth if multi-workspace)✓Iterate conversations with `?starting_after={cursor}` until exhausted✓Pull each conversation's `parts` (replies, notes, assignments) — that's where the real content lives✓Extract Help Center articles + collections + sections (preserving the slug for redirects)✓Throttle the extractor to stay under 1,000 req/min; the resumable cursor means it's restartableYou walk away withA re-runnable extract script + a reconciliation report against your Intercom Reports totals.
Build + weekly demos
4-6 weeksPostgres-backed Inbox, a lean React Messenger widget shipped from your CDN, a Next.js Help Center on your own domain, and an LLM-backed AI assist that lives in your repo.
✓Build the Inbox: assignment, threads, full-text search across closed tickets (a single GIN index)✓Build the Messenger widget: lazy-loaded, opens a WebSocket only on click, mint `user_hash` server-side for identity✓Migrate the Help Center to MDX articles served from your own domain (links no longer rel=nofollow by default)✓Wire Claude or GPT for AI assist — your prompts live in git, you pay your model provider directly✓Outbound runs on Inngest + Resend — no $99 add-on, no 500-message capYou walk away withA working chat + helpdesk + KB on a staging domain, with your team handling 10% of live tickets through it by end of phase.
Parallel run + Messenger cutover
2-3 weeksBoth Messenger widgets coexist behind a feature flag while we ramp the rollout from 10% to 100% of visitors. Inbound emails go to both inboxes; replies sync via a webhook bridge.
✓Dual-write inbound emails to both systems via a Cloudflare worker bridge✓Ramp the new Messenger widget from 10% → 50% → 100% over two weeks✓Disable Fin AI Triggers on the Intercom side to stop the per-resolution clock✓Daily reconciliation: tickets opened/closed, SLA breaches, CSAT averages✓Train your agents in two 60-minute sessions, recorded for the restYou walk away withA reconciliation dashboard + signed sign-off from the head of support.
Cutover + Intercom read-only
1 day + 90-day fallbackWe flip DNS for the Help Center subdomain, swap the Messenger script tag for the new widget, and lock Intercom to read-only. 301 redirects keep the SEO equity from the old /hc/ URLs.
✓Deploy the 301 redirect map for every /hc/ article URL → new path✓Swap the Messenger snippet on the production site✓Cut email routing to the new Inbox✓Lock Intercom to read-only (revoke write permissions on the workspace)✓Cancel auto-renewal in writing the same dayYou walk away withCutover Runbook + 301 redirect map + a quiet inbox where the renewal email used to land.
The Intercom APIs we'd actually hit
Concrete endpoints we use to extract your data during the parallel-run phase. We keep the extract scripts — they're useful at every renewal.
GET https://api.intercom.io/conversationsGET https://api.intercom.io/conversations/{id}POST https://api.intercom.io/conversations/searchGET https://api.intercom.io/contactsGET https://api.intercom.io/companiesGET https://api.intercom.io/articlesGET https://api.intercom.io/help_center/collectionsGET https://api.intercom.io/tagsThe Intercom-specific gotchas
Things we've learnt the hard way (or that the documentation understates). We'll surface these on the kickoff call so nobody is surprised in week 6.
- ⚠REST API rate limit defaults to 1,000 requests/minute per workspace and is lower for some endpoints — the conversations extract is the long pole. Use the resumable cursor and exponential backoff on 429s.
- ⚠Conversations are paginated with `starting_after` cursors, not page numbers — if you don't respect the cursor you'll silently skip records.
- ⚠The Messenger widget identifies logged-in users via a signed `user_hash` that you mint server-side with a shared secret. During parallel run, the new widget needs the same secret-derivation strategy or sessions break.
- ⚠Help Center articles live on an `intercom.help` subdomain — preserve the URL slug to article ID mapping for 301 redirects, or you'll lose every Google ranking the docs have earned.
- ⚠Fin AI continues to bill per resolution during the parallel run if you leave Triggers active. Disable Fin Triggers explicitly when phase 5 starts or you'll pay twice.
- ⚠Workflow JSON is read-only — you can read the rules but can't reimport them. Rebuild the logic from the inventory in phase 1, not from any 'import' tool (there isn't one).
- ⚠Soft-deleted contacts and conversations still show up via the API unless filtered — check the `state` field rather than assuming the list is clean.
What stays where it is
Migrations work because they're scoped honestly. Here's what we don't move — by design.
- ·Fin AI prompts and topics — replaced with Claude/GPT calls in your own code, with your help articles as the retrieval source
- ·Custom Bots — rewritten as TypeScript flows you can read in a PR
- ·Series outbound campaigns — rebuilt on Inngest + Resend with no 500-message cap
- ·Marketplace / Connector apps — replaced by direct API calls to the underlying SaaS
- ·Native mobile SDKs — most teams use email + web chat; if mobile push matters we scope it separately
- ·Phone / Switch — telephony stays in your existing dialer (Aircall, Dialpad, Twilio)
Get a Intercom-shaped migration plan.
Tell us your seat count, contract end date, and the integrations you can't lose. We'll come back within a business day with a fixed-price scope and a timeline tuned to your renewal.
Scope a Intercom migration
One business day. NDA + DPA on request.