Skip to main content

Connect Intercom end to end

The Intercom integration is a bidirectional conversation loop:
  • Inbound — contact, conversation, and ticket events from your Intercom workspace arrive on a signature-verified webhook receiver. Contact events upsert into your Orbit contact book, and conversation events are resolved to a live contact so inbound threads (and the campaigns that trigger off them) have full Orbit context.
  • Outbound — Orbit posts replies, internal notes, and open/close actions back onto the Intercom conversation an Orbit contact is attached to, so an agent working the Orbit inbox keeps the customer’s Intercom thread in sync.
This guide is the numbered checklist operators run when they wire a workspace up. The endpoint map it links back to is /api-reference/integrations — this page is the “do this, then this” walkthrough for the same surface.

What you’ll set up

  1. An OAuth connection from Orbit to your Intercom workspace — via the generic connect route or the dedicated Intercom OAuth route (both end at the same connection).
  2. Automatic topic registration — on a successful connect, Orbit programs webhook subscriptions on your workspace for the contact, conversation, and ticket event set.
  3. The inbound event stream — HMAC-verified events, deduplicated per notification, resolved to your tenant and your contacts.
  4. The outreach path — replies, internal notes, and open/close actions posted from Orbit back onto the Intercom conversation.
  5. Failure-mode recovery — what non-blocking tenant-setup failure means and how to re-register.

Step 1 — Connect via OAuth (admin only)

There are two connect paths. Pick one — they converge on the same connection object and the same post-connect setup.
Owner or admin role required, plus the integrations:write scope on the API key — this is the only step that touches provider credentials. The response returns an auth_url; redirect the browser there and complete the Intercom consent screen.

Option B — the dedicated Intercom OAuth route

Use this when you want a branded “Install on Intercom” button or you don’t want to go through the generic connect flow:
The /oauth/start endpoint mints a signed, short-lived state token (10-minute TTL) — the raw organization id is never forwarded to Intercom — and returns the Intercom auth_url. Redirect the operator to that URL. Intercom sends the browser back to GET /api/v1/integrations/intercom/oauth/callback, a public route: browsers cannot carry the session cookie reliably across Intercom’s top-level redirect (especially Safari with tracking protection), so the callback is mounted before auth and the signed state round-trip is the authentication. The callback verifies the signature and TTL, exchanges the code for a workspace token, reads the workspace id, and runs post-connect setup. A declined consent screen returns 400 INTERCOM_OAUTH_ERROR with the provider’s reason; a tampered or expired state returns 400 INVALID_OAUTH_STATE / 400 OAUTH_STATE_EXPIRED.
After OAuth consent, check GET /api/v1/integrations — the Intercom row should report a connected state. The Step section below confirms topic registration.

Step 2 — What Orbit configures after a successful connect

Either connect path ends in the same automatic tenant setup:
  1. Orbit resolves the workspace id (app_id) and access token from the OAuth callback (or, on the generic path, from the integration server connection record).
  2. The workspace access token, the webhook signing secret, and the confirmed topic set are persisted on the tenant’s Intercom connection record. Credentials are encrypted at rest.
  3. Orbit registers the full topic set on your workspace as one active subscription pointing at the Orbit receiver URL — before registering, it lists your existing subscriptions and skips topics already covered, so re-connecting never creates duplicate subscriptions.
  4. Re-registration is idempotent — running connect again refreshes the stored token and re-confirms topics in place.
The registered topic set covers the full contact, conversation, and ticket lifecycle:
Connection stays healthy even if some topics fail to register — events for the missing topics just won’t flow until you re-register (Step 5). The connection record keeps the confirmed topic list so the integration status surface can report drift.

Step 3 — The receive path: inbound events into Orbit

Intercom delivers each event as a single POST to https://api.orbit.devotel.io/api/v1/integrations/webhooks/intercom. The receiver:
  1. Verifies the sender. Intercom signs payloads with X-Hub-Signature: sha1=<hex>, an HMAC-SHA1 of the raw request body keyed by the OAuth app’s client secret. Orbit compares hex digests in constant time and fails closed — when the client secret is unset the receiver is disabled (503) rather than accepting unverified events; a bad signature is rejected. Reconnecting rotates nothing you need to redo manually.
  2. Resolves the tenant. The event’s app_id (your workspace id) is looked up against the connection records written at connect time so the event lands in the right tenant. Events for a workspace no tenant owns are rejected.
  3. Deduplicates. Intercom retries a notification up to 30 times over roughly 8 hours until it sees a 2xx. Orbit stores one row per (topic, notification id) and no-ops re-deliveries, so retries never duplicate contact updates.
  4. Dispatches by topic:
    • Contact events upsert the Orbit contact (email, phone, name, linked on the Intercom contact id); contact.deleted soft-stamps the linked Orbit contact.
    • Conversation events are resolved to the linked Orbit contact and mirrored with their conversation and assigning-admin ids, so an inbound Intercom thread carries full context in Orbit and can drive inbox views and campaign triggers.
    • Ticket events are persisted for the campaign engine to build on.
Acknowledge budget: Intercom expects a 2xx within 5 seconds, and retries on anything else. Events are persisted and dispatched inside that budget.

Step 4 — The outreach path: writeback into Intercom

When an agent or the AI layer answers an Intercom-linked contact from Orbit, Orbit posts back onto the Intercom conversation:
  • Reply resolution — Orbit finds the most recent Intercom conversation attached to the contact and, when the conversation names an assignee, posts as that admin. The admin who installed the app is the fallback author.
  • Public reply vs internal note — a public reply goes on the customer’s thread; an internal note (note) is admin-only — the AI agent uses it to leave context on the thread before assigning.
  • Open and close — an Orbit-side conversation close can post a close on the Intercom thread, and a reopened thread can post open, so both inboxes agree on state.
  • Fail-open — a writeback failure (revoked token, Intercom outage) is logged and audited, but never blocks the primary send in Orbit. If the contact has no Intercom conversation on file, Orbit falls back to its normal outbound channel.

Step 5 — Failure modes and re-registration

Post-connect setup is deliberately non-blocking: a topic-registration failure never makes a connect look like it failed — the connection is live, and unregistered topics are recoverable.
Webhook deliveries that fail vanish only after Intercom exhausts its retries (~30 attempts over ~8 hours). Because duplicates dedupe by notification id, a redelivery after recovery is safe.

Generic connect vs dedicated Intercom OAuth — which to use

Both paths land in the same post-connect setup and produce the same connection record. Do not run both — pick one.