> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# Connect Intercom

> Generate an access token, copy your workspace and teammate IDs, enter credentials, configure the webhook, and choose how handoffs are routed.

export const IntercomFlow = () => {
  const BEAM_COLOR = "#22c55e";
  const renderBeam = ({id, d, duration = 2.8, delay = 0, reverse = false}) => {
    const values = reverse ? {
      x1: "110%;-10%",
      x2: "120%;0%"
    } : {
      x1: "-10%;110%",
      x2: "0%;120%"
    };
    return <g key={id}>
        <path d={d} stroke="currentColor" strokeOpacity="0.18" strokeWidth="1.5" fill="none" strokeLinecap="round" />
        <path d={d} stroke={`url(#${id})`} strokeWidth="2" fill="none" strokeLinecap="round" />
        <defs>
          <linearGradient id={id} gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="0">
            <stop offset="0%" stopColor={BEAM_COLOR} stopOpacity="0" />
            <stop offset="45%" stopColor={BEAM_COLOR} stopOpacity="1" />
            <stop offset="55%" stopColor={BEAM_COLOR} stopOpacity="1" />
            <stop offset="100%" stopColor={BEAM_COLOR} stopOpacity="0" />
            <animate attributeName="x1" values={values.x1} dur={`${duration}s`} begin={`${delay}s`} repeatCount="indefinite" />
            <animate attributeName="x2" values={values.x2} dur={`${duration}s`} begin={`${delay}s`} repeatCount="indefinite" />
          </linearGradient>
        </defs>
      </g>;
  };
  const CH_X = 90, IC_X = 420, OCX_X = 760;
  const CH_Y_TOP = 100, CH_Y_BOT = 220, MID = 160;
  const CH_R = 26;
  const bTop = `M ${CH_X + CH_R},${CH_Y_TOP} C ${CH_X + CH_R + 120},${CH_Y_TOP} ${IC_X - 44 - 120},${MID} ${IC_X - 44},${MID}`;
  const bBot = `M ${CH_X + CH_R},${CH_Y_BOT} C ${CH_X + CH_R + 120},${CH_Y_BOT} ${IC_X - 44 - 120},${MID} ${IC_X - 44},${MID}`;
  const bMid = `M ${IC_X + 44},${MID} C ${IC_X + 44 + 110},${MID - 20} ${OCX_X - 44 - 110},${MID - 20} ${OCX_X - 44},${MID}`;
  const bMidRev = `M ${IC_X + 44},${MID} C ${IC_X + 44 + 110},${MID + 20} ${OCX_X - 44 - 110},${MID + 20} ${OCX_X - 44},${MID}`;
  return <div className="zendesk-flow not-prose my-8 w-full">
      <div className="zendesk-flow-frame relative w-full overflow-hidden rounded-md border border-black/10 bg-white px-4 py-6 dark:border-white/10 dark:bg-zinc-950">
        <div className="zendesk-flow-grid pointer-events-none absolute inset-0" aria-hidden />
        <svg viewBox="0 0 840 320" preserveAspectRatio="xMidYMid meet" xmlns="http://www.w3.org/2000/svg" className="relative z-[1] block w-full text-zinc-500 dark:text-zinc-400" role="img" aria-label="Intercom flow: web messenger and email converge on Intercom, OpenCX posts as a designated teammate">
          {renderBeam({
    id: "ic-t",
    d: bTop,
    duration: 3.0,
    delay: 0
  })}
          {renderBeam({
    id: "ic-b",
    d: bBot,
    duration: 3.0,
    delay: 0.6
  })}
          {renderBeam({
    id: "ic-m",
    d: bMid,
    duration: 2.6,
    delay: 0.2
  })}
          {renderBeam({
    id: "ic-mr",
    d: bMidRev,
    duration: 2.6,
    delay: 1.5,
    reverse: true
  })}

          <g className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "500 11px ui-sans-serif, system-ui, sans-serif"
  }}>
            <text x={(CH_X + IC_X) / 2} y={CH_Y_TOP - 18} textAnchor="middle">web chat</text>
            <text x={(CH_X + IC_X) / 2} y={CH_Y_BOT + 30} textAnchor="middle">email</text>
            <text x={(IC_X + OCX_X) / 2} y={MID - 46} textAnchor="middle">AI reply</text>
            <text x={(IC_X + OCX_X) / 2} y={MID + 54} textAnchor="middle">handoff · route</text>
          </g>

          {}
          <g>
            <circle cx={CH_X} cy={CH_Y_TOP} r={CH_R} className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <g transform={`translate(${CH_X - 10} ${CH_Y_TOP - 10})`} className="fill-zinc-700 dark:fill-zinc-200">
              <path d="M 10 1 C 4.5 1 0 5 0 10 c 0 2 1 4 2.6 5.5 L 2 19 l 3.8 -1.4 c 1.3 0.5 2.7 0.7 4.2 0.7 c 5.5 0 10 -4 10 -9 S 15.5 1 10 1 Z" fill="currentColor" />
            </g>
            <text x={CH_X} y={CH_Y_TOP + CH_R + 18} textAnchor="middle" className="fill-zinc-600 dark:fill-zinc-300" style={{
    font: "500 11px ui-sans-serif, system-ui, sans-serif"
  }}>Messenger</text>
          </g>
          {}
          <g>
            <circle cx={CH_X} cy={CH_Y_BOT} r={CH_R} className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <g transform={`translate(${CH_X - 10} ${CH_Y_BOT - 7})`} className="fill-none stroke-zinc-700 dark:stroke-zinc-200" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
              <rect x="0" y="0" width="20" height="14" rx="1.5" />
              <path d="M 0,2 L 10,9 L 20,2" />
            </g>
            <text x={CH_X} y={CH_Y_BOT + CH_R + 18} textAnchor="middle" className="fill-zinc-600 dark:fill-zinc-300" style={{
    font: "500 11px ui-sans-serif, system-ui, sans-serif"
  }}>Email</text>
          </g>

          {}
          <g>
            <circle cx={IC_X} cy={MID} r="44" className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <foreignObject x={IC_X - 22} y={MID - 22} width="44" height="44">
              <div className="flex h-full w-full items-center justify-center">
                <img src="/images/integrations/intercom.svg" alt="" className="block h-8 w-8 object-contain dark:hidden" />
                <img src="/images/integrations/intercom-dark.svg" alt="" className="hidden h-8 w-8 object-contain dark:block" />
              </div>
            </foreignObject>
            <text x={IC_X} y={MID + 66} textAnchor="middle" className="fill-zinc-700 dark:fill-zinc-200" style={{
    font: "600 12px ui-sans-serif, system-ui, sans-serif"
  }}>Intercom</text>
            <text x={IC_X} y={MID + 80} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "400 10.5px ui-sans-serif, system-ui, sans-serif"
  }}>shared inbox</text>
          </g>

          {}
          <g>
            <circle cx={OCX_X} cy={MID} r="48" className="fill-none" stroke={BEAM_COLOR} strokeOpacity="0.25" strokeWidth="1.5">
              <animate attributeName="r" values="46;56;46" dur="3.6s" repeatCount="indefinite" />
              <animate attributeName="stroke-opacity" values="0.35;0;0.35" dur="3.6s" repeatCount="indefinite" />
            </circle>
            <circle cx={OCX_X} cy={MID} r="44" className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
            <foreignObject x={OCX_X - 34} y={MID - 18} width="68" height="36">
              <div className="flex h-full w-full items-center justify-center">
                <img src="/logo-light.svg" alt="" className="block h-full w-full object-contain dark:hidden" />
                <img src="/logo.svg" alt="" className="hidden h-full w-full object-contain dark:block" />
              </div>
            </foreignObject>
            {}
            <g>
              <circle cx={OCX_X + 30} cy={MID + 30} r="14" className="fill-white stroke-black/10 dark:fill-zinc-900 dark:stroke-white/10" strokeWidth="1" />
              <g transform={`translate(${OCX_X + 30 - 8} ${MID + 30 - 9})`} className="fill-none stroke-zinc-700 dark:stroke-zinc-200" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
                <circle cx="8" cy="6" r="3.2" />
                <path d="M 2 17 C 2 12 14 12 14 17" />
              </g>
            </g>
            <text x={OCX_X} y={MID + 66} textAnchor="middle" className="fill-zinc-700 dark:fill-zinc-200" style={{
    font: "600 12px ui-sans-serif, system-ui, sans-serif"
  }}>OpenCX</text>
            <text x={OCX_X} y={MID + 80} textAnchor="middle" className="fill-zinc-500 dark:fill-zinc-400" style={{
    font: "400 10.5px ui-sans-serif, system-ui, sans-serif"
  }}>posts as Admin teammate</text>
          </g>
        </svg>
      </div>
    </div>;
};

One-time setup: enter your Intercom credentials, pick the teammate the AI replies as, paste the webhook URL into Intercom, and choose how handoffs are routed.

<IntercomFlow />

<Info>
  This page covers the shared Intercom connection. Once connected, see the [Web](/integrations/intercom/channels/web) or [Email](/integrations/intercom/channels/email) channel pages for per-channel verification steps.
</Info>

## Before you start

<AccordionGroup>
  <Accordion title="Intercom workspace with API access" icon="key">
    You need an Intercom workspace on a plan that includes API access. You also need admin-level permissions to generate access tokens in the Developer Hub.
  </Accordion>

  <Accordion title="Admin access in OpenCX" icon="shield-check">
    Only organization admins can connect integrations. Confirm your role at [**Settings → Organization**](https://platform.open.cx/settings).
  </Accordion>

  <Accordion title="A dedicated Intercom teammate for the AI" icon="user-plus">
    Designate or create a teammate that represents the AI (for example, "AI Assistant"). Customers see this teammate as the author of every AI reply, so a dedicated bot account is strongly preferred over a real teammate's account. You'll copy this teammate's ID in step 3.
  </Accordion>
</AccordionGroup>

## Setup

<Steps>
  <Step title="Generate an access token">
    In Intercom, go to **Settings → Integrations → Developer Hub**. Create a new app if you don't already have one, or open an existing app.

    Inside the app, open **Authentication** and copy the **Access token** displayed beneath the app name. You can return to this page at any time to view the token again.

    <Warning>
      Treat this access token like a password. It grants full read and write access to your Intercom conversations and contacts — don't share it, don't paste it into shared channels or tickets, and rotate it immediately if you suspect it has leaked.
    </Warning>
  </Step>

  <Step title="Copy your workspace ID">
    In Intercom, go to **Settings → Workspace → General** and copy the **App ID** field. Intercom uses "App ID" and "Workspace ID" interchangeably — they refer to the same value.
  </Step>

  <Step title="Copy your AI teammate ID">
    Use the dedicated teammate from the prerequisites (create one first if you haven't).

    In Intercom, go to **Settings → Workspace → Teammates** and click the teammate. The teammate ID appears as the last segment of the URL on the profile page:

    ```
    app.intercom.com/a/apps/<WORKSPACE_ID>/admins/<TEAMMATE_ID>
    ```

    Copy `<TEAMMATE_ID>` — that's the value you'll paste into the **AI Admin ID** field in OpenCX.

    <Warning>
      Every AI-generated reply is posted as this teammate. Use a dedicated bot account (for example, "AI Assistant") rather than a real teammate to avoid confusion with your team's own replies.
    </Warning>
  </Step>

  <Step title="Enter credentials in OpenCX">
    Open [**Settings → Integrations**](https://platform.open.cx/settings/integrations) in your OpenCX dashboard and select **Intercom**. OpenCX generates a webhook URL the moment the modal opens — you'll use it in the next step.

    Fill in:

    | Field | Value |
    | - | - |
    | **Access token** | The token from step 1. |
    | **Workspace ID** | The App ID from step 2. |
    | **AI Admin ID** | The teammate ID from step 3. |

    Click **Save**. OpenCX validates the credentials by listing your Intercom conversations. If validation fails, double-check that the token has not been revoked and that your Intercom plan includes API access.
  </Step>

  <Step title="Configure the webhook">
    Still in the OpenCX modal, copy the **Webhook URL**.

    In Intercom, go to **Settings → Integrations → Developer Hub → choose your app → Webhooks** and paste the URL. See Intercom's [webhook setup guide](https://developers.intercom.com/docs/webhooks/setting-up-webhooks) for reference.

    Subscribe to these topics:

    * `conversation.user.created`
    * `conversation.user.replied`
    * `conversation.admin.replied`
    * `conversation.admin.noted`
    * `conversation.admin.assigned`
    * `conversation.admin.open.assigned`
    * `conversation.admin.closed`
    * `conversation.admin.opened`
    * `conversation.admin.snoozed`
    * `conversation.admin.unsnoozed`
    * `conversation.priority.updated`

    <Warning>
      Without the webhook, OpenCX cannot receive conversation events and the AI will not respond to any messages. If you later change the app or rotate the token, re-verify that the webhook is still pointing at the OpenCX URL.
    </Warning>
  </Step>

  <Step title="Configure handoff assignment">
    Choose what happens when the AI hands off a conversation:

    * **Unassigned** (default) — removes the AI teammate and leaves the conversation in your triage queue for any teammate to pick up.
    * **Specific teammate** — assigns to a named teammate on handoff.
    * **Specific team** — assigns to an Intercom team on handoff.
    * **Team and teammate** — assigns to both a team and a specific teammate simultaneously.
  </Step>

  <Step title="Enable full conversation sync (optional)">
    Open the **Sync Settings** tab inside the Intercom modal and toggle **Full Conversation Auto Sync** to sync every conversation in your Intercom workspace — not only the ones assigned to the AI teammate.

    <Info>
      Non-AI conversations are stored for reporting, insights, and supervision, and are **not billed** as AI interactions. With this on, the AI can also be brought into a conversation partway through by assigning it to the AI teammate.
    </Info>
  </Step>

  <Step title="Send a test message">
    Open your Intercom Messenger and send a test message. The AI should reply within a few seconds. Then say *"I want to talk to a human"* — you should see an internal handoff note appear, and the conversation should be unassigned (or reassigned per your handoff configuration).

    <Info>
      For channel-specific verification, see [Web](/integrations/intercom/channels/web#setting-up) or [Email](/integrations/intercom/channels/email#setting-up).
    </Info>
  </Step>
</Steps>

## Settings reference

All settings are configured at [**Settings → Integrations**](https://platform.open.cx/settings/integrations) → Intercom, across the **Connection**, **Handoff Settings**, and **Sync Settings** tabs.

| Setting | Purpose |
| - | - |
| **Default teammate** (AI Admin ID) | The Intercom teammate the AI replies as. Required. |
| **Default team** | Fallback team for routing. Optional. |
| **Handoff assignment** | Where conversations go on handoff: unassigned, specific teammate, specific team, or both team and teammate. |
| **Ignore first message** | Skip AI processing on the opening message. Useful when Intercom bots handle the greeting. |
| **Process on assignment** | Wait for the conversation to be assigned to the AI teammate before processing, instead of processing on the first message. |
| **Full conversation sync** | Configured in the **Sync Settings** tab. Stores every Intercom conversation in OpenCX — not just those assigned to the AI — for reporting and supervision. |
| **Forward unsupported attachments** | Pass PDF, video, and audio attachments to the AI as placeholder text so it can acknowledge them. |
| **Send citations as note** | Post an internal note linking to the AI's source citations in OpenCX after each reply. |
| **Company data sync** | Sync custom attributes from the contact's Intercom company to their OpenCX profile. Options: disabled, first company only, all companies. |
| **Custom attribute delay** | Seconds to wait before re-fetching conversation custom attributes after creation. Handles Intercom race conditions where attributes are set by workflows after the conversation is created. Max 10 seconds. |

## Link human teammates

After connecting Intercom, open **Settings → Linked Accounts** and find the **Intercom** section. Click **Sync**, then review the automatic email matches or select each member's Intercom account. Each Intercom teammate can be linked to only one OpenCX member in the workspace. Only teammates with an Inbox seat can be linked; Fin is not a human account mapping.

Changing mappings requires permission to manage integrations. Members who can view integrations or manage members can view the mappings. The mapping controls who authors an inbox reply, internal note, or manual status change in Intercom. An unlinked sender uses the configured default teammate.

## Map snooze to an OpenCX status

In **Settings → Integrations → Intercom → Sync Settings → Snooze**, select an open session status under **Snoozed status** and set **Snooze duration (hours)**. The default duration is 24 hours. Save the settings.

Applying that status in OpenCX snoozes the linked Intercom session. Clearing it opens the Intercom session again. Intercom snooze and unsnooze events update that status in OpenCX; a customer reply that opens the Intercom session also clears it. Other OpenCX statuses are preserved when an unsnooze arrives. Select no mapped status to disable snooze synchronization.

When Intercom is your ticketing system, a new customer reply received directly in OpenCX also returns an open, linked session with the mapped snooze status to native **Open**, with no custom status, and clears snooze in Intercom. Other custom statuses, the assigned teammate, and human handoff remain unchanged. Duplicate replies and replies that predate a newer recorded snooze do not clear it.

## Disconnecting

To remove the Intercom integration, open [**Settings → Integrations**](https://platform.open.cx/settings/integrations) → Intercom and click **Disconnect**. This deletes stored credentials and stops webhook processing. Existing OpenCX sessions are preserved but no longer receive updates from Intercom.

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Conversations" icon="messages" href="/integrations/intercom/conversations">
    How messages flow, handoff steps, and tags.
  </Card>

  <Card title="Channels" icon="grid-2" href="/integrations/intercom/channels/web">
    Per-channel implementation details for Web and Email.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/integrations/intercom/troubleshooting">
    Credentials failing, webhook silent, AI not replying.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.