> ## 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`

    <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. |

## 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>
