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

# Plain

> Capture support threads from Plain and act on them with the agent

export const Prompt = ({text, variant = 'accent'}) => {
  const [copied, setCopied] = useState(false);
  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {}
  };
  const clipboardIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <title>Copy</title>
            <rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
            <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
        </svg>;
  const checkIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <title>Copied</title>
            <polyline points="20 6 9 17 4 12" />
        </svg>;
  const promptIcon = <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" style={{
    flexShrink: 0,
    opacity: 0.4
  }}>
            <title>Prompt</title>
            <path d="M20 2H2v20h2V4h16v12H6v2H4v2h2v-2h16V2zM6 7h12v2H6zm8 4H6v2h8z" />
        </svg>;
  return <div className={`prompt prompt-${variant}`} style={{
    marginTop: '12px',
    marginBottom: '12px'
  }}>
            {promptIcon}
            <span className="prompt-text">{text}</span>
            <button className="prompt-copy" onClick={handleCopy} title="Copy to clipboard" type="button">
                {copied ? checkIcon : clipboardIcon}
            </button>
        </div>;
};

The Plain integration captures support threads from your Plain workspace in real time. Customer emails, chat messages, and your team's internal notes flow into Modem, where they are grouped into [topics](/docs/guides/topics), classified by type, and linked to the [people and companies](/docs/guides/people) behind them. The [Modem Agent](/docs/features/agent) can also act on Plain directly: look up threads and customers, reply to customers, add internal notes, and change a thread's status, priority, labels, and assignee.

## How it works

Modem connects to Plain with a **machine-user API key** you create in your Plain workspace. When you paste the key, Modem validates it, fetches your workspace's Request signing secret, and registers a webhook target in Plain automatically. From then on Plain pushes thread activity to Modem as it happens; every delivery is verified against the signing secret before it's processed.

API keys in Plain don't expire, so there's no re-authorization cycle. Capture is webhook-based and real-time: a new customer message typically shows up in Modem within a few minutes.

## Prerequisites

* **Owner or admin** role in your Modem organization, to connect and manage the integration
* Access to create machine users and API keys in your Plain workspace

## Setup

<Steps>
  <Step title="Create a machine-user API key in Plain">
    In Plain, go to **Settings** → **Machine users / API keys** and create a key. See [Permissions](#permissions) below for what it
    needs.
  </Step>

  <Step title="Paste the key into Modem">
    Go to **Settings** → **Integrations** → **Plain** in your Modem dashboard, paste the key, and click **Connect Plain**. Modem
    encrypts the key before storing it.
  </Step>

  <Step title="Modem registers its webhook">
    Modem validates the key, reads your workspace's Request signing secret, and registers a webhook target in Plain. New thread activity
    starts flowing immediately.
  </Step>

  <Step title="Optionally run a backfill">
    Import recent existing threads so ongoing conversations show up too. See [Historical Backfill](#historical-backfill) below.
  </Step>
</Steps>

## Permissions

The machine-user API key needs these permissions for capture:

| Permission | Why Modem needs it |
| - | - |
| Read access to threads and messages | Ingest thread timelines (emails, chats, notes) |
| Read access to customers | Link messages to the people behind them |
| `user:read` | Show teammates' real names and emails, not a placeholder |
| `webhookTarget:create` | Register Modem's webhook target automatically |
| `webhookTarget:delete` | Remove Modem's webhook target when you disconnect |
| `workspaceHmac:read` | Fetch the Request signing secret used to verify each delivery |

To let the agent act on Plain, also grant the permissions for the actions you want it to take:

| Permission | Agent action |
| - | - |
| `thread:reply` | Reply to a customer on a thread |
| `note:create` | Add an internal note |
| `thread:edit` | Mark a thread done or todo, snooze it, or change its priority |
| `label:create`, `label:delete` | Add or remove labels |
| `thread:assign`, `thread:unassign` | Assign or unassign a thread |

Leave these out to keep the agent read-only in Plain. If the agent tries an action the key isn't allowed to take, Plain rejects it and the agent tells you which permission is missing.

<Note>
  If your key can't be granted `workspaceHmac:read`, use the **enter it manually** option on the connect form and paste the secret from
  Plain under **Settings** → **Request signing** instead.
</Note>

## What Gets Captured

### Thread messages

For each Plain thread, Modem captures the timeline as a single conversation:

* **Customer emails** received and support replies sent
* **Chat messages** from both sides
* **Internal notes** written by your team, marked as internal

Email bodies are cleaned before they're stored: quoted-reply chains and signature blocks are stripped, and inline attachment data is collapsed to a short placeholder. Attachment files themselves are not ingested.

### Thread metadata

Each thread's title, status, priority, labels, assignee, and a link back to the thread in Plain. Status, priority, and label changes are recorded on the conversation timeline for context. Only real messages feed topic analysis.

### Customers

Plain customer profiles (name and email) sync as they're created and updated, and message authors are resolved to Modem [people](/docs/guides/people) by email address. For live activity, your own teammates are matched to their real email addresses too, so support replies link to existing team members instead of creating duplicates. Backfilled history uses teammates' display names only. Plain's automation and system actors are flagged as bots.

## Historical Backfill

Connecting only captures activity from that point forward. To pull in recent history, run the optional backfill from **Settings** → **Integrations** → **Plain**: it imports threads created in the **last 30 days**, up to **500 threads**, along with their messages.

The backfill runs in the background and doesn't block real-time capture. Plain's API is rate-limited, so a busy workspace can take a while; the card shows progress and you can re-run it if it fails.

## Using the Agent with Plain

The Modem Agent can query your captured Plain data like any other source, and it can act on Plain directly through Plain's GraphQL API: looking up live threads, customers, and labels; replying to customers; adding internal notes; and changing a thread's status, priority, labels, and assignee.

<Prompt text="What are customers writing in about in Plain this week?" />

<Prompt text="Summarize the highest-priority open support threads in Plain" />

<Prompt text="Reply to Plain thread T-142 letting the customer know the fix ships Friday" />

<Prompt text="Add an internal note to that thread linking the Linear ticket, then mark it done" />

* **Approval prompts.** Every action asks for your approval in the chat before it runs, unless you chose to always approve that action. Lookups never need approval.
* **Replies reach the customer.** A reply is sent to the customer through the thread's channel, usually email. Use an internal note for anything only your team should see.

<Note>
  Plain attributes API actions to the machine user that owns the API key, so agent replies and notes appear in Plain under that machine
  user. Customers see the machine user's **public name**.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Connecting fails with a permission error">
    The most common gap is `workspaceHmac:read`: without it Modem can't fetch the Request signing secret automatically. Grant the
    permission to the machine user, or use the manual fallback on the connect form and paste the secret from Plain under **Settings** →
    **Request signing**. Also confirm the key has read access to threads and customers plus `webhookTarget:create`.
  </Accordion>

  <Accordion title="The agent can't reply, add notes, or change threads">
    The API key is missing the permission for that action. The agent's error names the permission Plain asked for. Add it to the machine
    user's API key in Plain; see the agent actions table under [Permissions](#permissions).
  </Accordion>

  <Accordion title="New threads aren't appearing">
    Confirm the integration shows as connected in **Settings** → **Integrations** → **Plain**, then allow a few minutes for webhook
    delivery and processing. Modem only captures activity that happens after you connect; run the [backfill](#historical-backfill) for
    recent existing threads. If nothing arrives, disconnecting and reconnecting registers a fresh webhook target.
  </Accordion>

  <Accordion title="The backfill seems incomplete">
    The backfill covers threads created in the last 30 days, up to 500 threads, so older or excess threads aren't imported. If a run
    failed, the card shows the error and a **Run again** button; re-running is safe and won't duplicate messages. If it still looks
    wrong, contact [support@modem.dev](mailto:support@modem.dev).
  </Accordion>

  <Accordion title="Authors aren't linking to people">
    Message authors are matched to Modem people by email address. If a Plain customer has no email on their profile, their activity
    won't be linked automatically.
  </Accordion>
</AccordionGroup>

## Disconnecting

To disconnect Plain:

1. Go to **Settings** → **Integrations** → **Plain**
2. Click **Disconnect** and confirm

Modem stops accepting deliveries from the workspace and attempts to remove the webhook target it registered in Plain. Removal is best-effort: if the stored API key has already been revoked or Plain's API is unavailable, the disconnect still completes and you may need to delete the target in Plain yourself. Historical data remains in Modem after disconnecting.

## Related

<CardGroup cols={2}>
  <Card title="The Modem Agent" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/bot.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=2496f9106cb54fa9f4e27ad1f8f3a171" href="/docs/features/agent" width="22" height="22" data-path="icons/bot.svg">
    Query and act on your captured Plain conversations from the web.
  </Card>

  <Card title="Topics" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/label-alt-multiple.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=e7fbaf23c28396ac670b89cf38e1e4a6" href="/docs/guides/topics" width="24" height="24" data-path="icons/label-alt-multiple.svg">
    See how support threads are grouped into themes and classified.
  </Card>

  <Card title="Companies & People" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/contact.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=727cb0ef6c8547993c6acfdaa30bd837" href="/docs/guides/people" width="24" height="24" data-path="icons/contact.svg">
    Understand how Plain customers are linked into unified profiles.
  </Card>

  <Card title="All Integrations" icon="https://mintcdn.com/modem-844d7a4a/Wr2r4IRr97lNQiQb/icons/link.svg?fit=max&auto=format&n=Wr2r4IRr97lNQiQb&q=85&s=e774d33588635d44c6c935b78ed55f13" href="/docs/integrations/overview" width="24" height="24" data-path="icons/link.svg">
    Browse every data source and agent tool.
  </Card>
</CardGroup>


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