# Plain connector (https://docs.ctxpipe.ai/docs/connections/source-connectors/plain)

The **Plain connector** writes Help Center articles and support threads from
[Plain](https://www.plain.com) into a [Workspace's](/docs/workspaces) GitHub
repository. ctxpipe then indexes them like other knowledge files. Agents can read
your support documentation and see what customers report. A source file in the
Workspace holds the scope. A pull request adds it, so a person reviews the
scope before content syncs.

ctxpipe only reads from Plain. It does not change threads, articles, or
customers. The one write is a webhook target for thread activity, which ctxpipe
adds and removes.

## What is mirrored

You select Help Centers, thread labels, or both, for each Workspace.

* **Help Center:** one file for each published article, with its group and
  its body as Markdown. Images are text stubs in this version.
* **Threads:** one file for each of the 100 newest threads with a label. A
  thread file has the ref, status, priority, labels, the customer name, and
  the first 50 messages in order, each as a quote. Internal notes are marked.
  A longer thread says that Plain has more messages.

ctxpipe writes people by name only. In thread text, ctxpipe removes email addresses,
phone numbers in common formats, and links that carry a credential. ctxpipe
keeps only `https:` links. A link with text keeps the text and loses the
link. A bare URL that is not `https:` becomes `[link removed]`. Other
personal data in the text can remain.

<Callout type="warn" title="Thread messages are personal data">
  Thread messages are text from your customers, and they can hold personal
  data. Git keeps every version of a file, so a removed thread stays in the
  history of the repository. Select labels that hold the threads your
  Workspace needs, and keep the repository private.
</Callout>

## Prerequisites

* A Plain admin who can add a machine user and an API key.
* A [Workspace](/docs/workspaces) whose repository the ctxpipe GitHub App can
  write to. The repository must use format 2 or higher. If it does not, the
  Workspace shows **Upgrade this Workspace first**. See
  [Upgrades](/docs/workspaces/settings#upgrades).
* Permission to merge the pull request that adds the source.

## Where the scope lives

The connection holds the API key only. The scope is in a source file in each
Workspace, at `sources/plain/<name>.md`. The front matter holds the Help
Center ids and the label type ids. The body is an optional description of what
the source is for.

```markdown
---
provider: plain
connection: con_example
helpCenters: [hc_01EXAMPLE]
labels: [lt_01EXAMPLE]
---

Product documentation and bug reports for the support Workspace.
```

The scope goes live after the merge. See
[Workspace settings](/docs/workspaces/settings#sources) for draft scope and
live scope.

A Workspace can have many Plain source files, and each Workspace has its own
scope.

## Setup flow

<Steps>
  <Step>
    ### Create a machine user and an API key

    In Plain, open **Settings → Machine Users** and add a machine user for
    ctxpipe. Add an API key with only these permissions:
    `helpCenter:read`, `helpCenterArticle:read`,
    `helpCenterArticleGroup:read`, `labelType:read`, `label:read`,
    `thread:read`, `timeline:read`, `customer:read`, `user:read`,
    `machineUser:read`, `webhookTarget:create`, and `webhookTarget:delete`.
    Copy the key: Plain shows it one time.
  </Step>

  <Step>
    ### Connect Plain

    In ctxpipe, open **Connectors**, select **Add connection**, then select
    **Plain**. Paste the key and select **Connect Plain**. ctxpipe checks the key
    and its permissions, keeps it encrypted, and adds one webhook target for
    thread activity.
  </Step>

  <Step>
    ### Add to Workspaces

    The next step is **Add to Workspaces**. Select the Workspaces that sync
    from Plain. Then select the Help Centers and labels. When you select more
    than one Workspace, choose **Same scope for each Workspace** or **A
    different scope for each Workspace**.

    Choose **Add to Workspaces**. You can add the connection to a Workspace
    later. Expand the connector on **Connectors**. When no Workspace uses the
    connection, choose **Add to a Workspace**. Otherwise, choose **Manage**.
  </Step>

  <Step>
    ### Merge the pull requests

    ctxpipe opens one pull request for each Workspace. Each pull request adds
    `sources/plain/<name>.md`. The dialog shows **Merge the pull request** (or
    **Merge the pull requests**) with a link to each one. Review the selected
    Help Centers and labels, and the repository audience, then merge.

    After each merge, the dialog shows **Pull request merged**. The source does
    not sync before the merge.
  </Step>

  <Step>
    ### Wait for the first sync

    After GitHub reports the merge, ctxpipe reads the source file and writes the
    first Plain files. The Workspace indexes the new files after that. See
    [Indexing](/docs/connections/ingestion) for the lifecycle.
  </Step>
</Steps>

## Change what syncs

Edit, rename, or remove a source in the **Settings** of the Workspace. See
[Workspace settings](/docs/workspaces/settings#sources). When you remove a
Help Center or a label from the scope, ctxpipe deletes its files in a sync
commit.

To change the Workspaces of the connection, use **Manage** on the connector
card. **Manage** opens the same **Add to Workspaces** step. It starts from the
current Workspaces and scopes.

## Files in the repository

```text
plain/help-centers/<help-center-id>/<slug>--<article-id>.md
plain/threads/labels/<label-id>/<thread-id>.md
```

The source owns these folders. Do not edit the files: ctxpipe writes them again
on each sync. When an article is unpublished, or a thread leaves the newest
100 of its label, ctxpipe deletes its file in the same commit.

## Keeping content current

* **Thread webhook:** a new message, a note, or a label change on a thread
  starts a sync of the labels at the end of a 10-minute window. More events in
  the same window start no more syncs.
* **Daily sync:** ctxpipe syncs each connection once a day. Help Center articles
  use this sync, because Plain sends no article events.
* **Sync now:** an owner or admin can select **Sync now** in the menu of the
  connector card.

## Verify the complete flow

1. Connect Plain and confirm that the name of the Plain workspace appears on
   **Connectors**.
2. Choose **Add to Workspaces**, select a Workspace, and select at least one
   Help Center or label.
3. Merge the pull request that adds `sources/plain/<name>.md`.
4. Confirm that the Workspace repository has files under `plain/`.
5. Add a note to a real thread with a selected label, not a Plain test
   thread. Confirm that the thread file changes after the 10-minute window.
6. Confirm that the Workspace index is ready in its **Settings**.

Steps 3 and 4 test the GitHub push webhook and the first sync. Step 5 tests
the Plain webhook delivery.

## Troubleshooting

### A test thread does not sync

Plain shows a test thread only to the person who created it, so the API key
cannot read it. To test the thread sync, send an email to your support
address, and add a selected label to the new thread.

### A label or a Help Center does not sync

Plain refuses a read when the key does not have a permission in the list
above. The source can still show OK. Add the missing permission to the key
in Plain, then select **Sync now** in the menu of the connector card.

### The setup names missing permissions

The key does not have every permission in the list. Create a new key on the
machine user with all of them, and paste it.

### Add to a Workspace shows an error

The dialog shows a message about the format, the write access, or your role.
See [Add source shows an error](/docs/workspaces/settings#add-source-shows-an-error).

### No pull request appears

Confirm that the GitHub App has write access to the Workspace repository. If
the dialog reports an error, close it and try again.

### The source shows a status other than OK

Read the status and the reason of the row in **Settings**. See
[Source status](/docs/workspaces/settings#source-status).

When a selected Help Center or label is deleted or archived in Plain, ctxpipe
tries it in three sync cycles and keeps its files. Then the source shows
**Out of access**. Remove the Help Center or the label from the source.

### The card says that threads sync once a day

Plain did not accept the webhook target. Plain sends webhooks only to a
public HTTPS address, and a workspace can have at most 25 targets. Select
**Reconnect Plain** on the card and paste the key again to try again, or use
the daily sync and **Sync now**. A reconnect replaces the target, so it also
helps when someone deleted the target in Plain.

### The card shows “Needs reconnect”

Plain refused the saved key, for example because someone deleted it.
ctxpipe keeps the files and stops the sync. Select **Reconnect Plain** on
the card and paste a new key. A missing permission does not show here: see
[A label or a Help Center does not sync](#a-label-or-a-help-center-does-not-sync).

### Removing the connector

Choose **Remove connector** in the menu of the connector card. See
[Connection menu](/docs/connections#connection-menu) for what stays in Git.
ctxpipe also deletes the webhook target in Plain while the key works. When the
key no longer works, delete the target in **Settings → Webhooks** in Plain.

### More than one ctxpipe target in Plain

A failed request can leave an extra ctxpipe webhook target in Plain. ctxpipe
refuses its events. Delete each ctxpipe target in **Settings → Webhooks** in
Plain except the newest, or delete all of them and select **Reconnect Plain**.
