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

# Talk to Murph in Slack, Teams, Discord, or WhatsApp

> Authorize the shared Slack app or connect a branded Teams, Discord, or WhatsApp app, then approve its people and locations

Your team can talk to Murph where they already work: Slack, Microsoft Teams,
Discord, or WhatsApp. Each connection belongs to one Interchange account.
People still receive only the data and actions their linked Interchange
membership allows.

<Note>
  On the seller's Listing page, the Distribution tabs show each messaging
  channel's status: Slack always appears, showing **Install in Slack** once
  Interchange's Slack app is publicly available — until then it shows
  **Coming soon**. Microsoft Teams, Discord, and WhatsApp appear as tabs once
  the account is in early access for branded apps; until then they are
  offered in the **+ Add destination** picker. Every tab links to the secure
  setup pane (**Settings → Messaging apps**), where provider client secrets,
  bot tokens, Meta access tokens, and app secrets are entered — never in
  email, chat, or a support ticket. Buyer accounts, which have no Listing
  page, manage the same apps directly from **Settings → Messaging apps**.
  Branded messaging apps are currently available only to accounts enrolled in
  the pilot; the secure setup pane shows when the account is not enabled.
  Enrollment controls setup and administration only; it does not stop an
  already active provider installation.
</Note>

## Open messaging destinations

The Listing page's Distribution tabs (and, for buyer accounts, **Settings →
Messaging apps** directly) separate the shared app from customer-branded
apps:

* **Slack**'s tab shows **Install in Slack**, which opens Slack's
  authorization flow in a new tab, once Interchange's shared Slack app is
  publicly available. Slack is currently the only shared, one-click app.
  Finish authorization in Slack; Interchange does not show its installation
  status yet. Until the shared app is available, the tab shows **Coming
  soon**.
* **Microsoft Teams**, **Discord**, and **WhatsApp** each show a **Set up in
  Settings** button (**Manage in Settings** once an app already exists) that
  opens the secure setup pane. There, connect a Discord, Microsoft Teams, or
  WhatsApp app you created with the provider to the current Interchange
  account. It then shows the provider webhook endpoint, credential readiness,
  approved install locations, and linked people.

Every tab always carries a status chip: **Install available** once the
shared Slack app is public, **N connected** once at least one branded app is
registered for that channel, or **Not set up** before the first one is
registered. Only account admins additionally get the button to act on it —
**Install in Slack**, **Set up in Settings**, or **Manage in Settings**;
everyone else sees just the chip.

Each channel's Distribution tab lists at most 20 branded apps. Once a channel
has more than that, the tab shows the first 20 followed by a note reading
"Showing 20 of *N* branded apps — manage the full list in Settings," where
*N* is the channel's true total; the rest of the roster still exists and is
reachable from **Settings → Messaging apps**.

Shared Discord, Teams, and WhatsApp apps are not available. Customer-branded
Slack apps are also not available. WhatsApp is always reply-only. It does not
initiate conversations or send proactive or template notifications.

## Choose a channel

| Channel         | Where people can talk to the agent                        | How a conversation starts                                | Product-initiated notifications                                                                                          |
| --------------- | --------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Slack           | Personal chat and an approved workspace channel           | Send a message, or mention Murph in a channel            | Supported only for approved events and destinations captured from the authorized workspace                               |
| Microsoft Teams | Personal chat and an approved team or channel             | Send a personal message, or mention the app in a channel | Supported only for approved event types and locations where the app is installed; rollout is controlled per installation |
| Discord         | A user install or an approved server channel              | Run `/ask`, or mention the app in a server channel       | Supported only for approved event types and authorized install targets; rollout is controlled per installation           |
| WhatsApp        | A direct conversation with the registered business number | The person sends a text message                          | Not supported. The app replies only inside Meta's current user-initiated customer-service window                         |

Slack, Teams, and Discord keep separate conversations for separate install
locations. In Teams, a channel thread also keeps its own context. The initial Discord experience
correlates follow-up `/ask` commands but does not promise a native Discord
thread.

## Start a new conversation

Ordinary follow-up messages in the same approved location keep the linked
person's Murph context for up to 24 hours after the most recent message. After
24 hours without a message, Interchange automatically starts a new Murph
conversation before handling the next message. Messages and files from the
expired conversation are not included. In an enabled branded app, use the
reset command when you want to start over sooner:

* In a Discord `/ask`, enter `/reset` as the entire `question`. In an approved
  server channel, mention the bot followed only by `/reset`.
* In a Teams personal chat, send `/reset`. In an approved channel thread, reply
  in that thread and mention the app followed only by `/reset`.
* In WhatsApp, send `/reset` as the entire message.

Interchange creates a new conversation for that person in that provider
location. The next message does not include messages or files from the previous
conversation.

The reset applies only to the linked Interchange member who sent it and only in
that provider conversation or thread. It does not reset another person's
context, another channel, or another account. It also does not delete the old
provider transcript or Interchange audit history; it changes which Murph
conversation receives future messages. The shared Slack app follows its
existing channel and thread behavior and does not support this branded-app
`/reset` command.

## What you need before setup

Prepare the following for every branded app:

* A display name, short description, support URL, privacy-policy URL, and
  optional terms URL.
* Reviewed square and outline artwork that meets the provider's current app
  requirements, plus an accent color where supported.
* The Interchange account the app should use with Murph.
* The exact people and install locations that should be allowed to use it.

A branded setup uses a separate provider registration for the client. It is not
a theme that changes one shared marketplace listing per installation. Provider
naming, publisher, artwork, review, and app-count policies still apply.

## Pilot rollout

Start with one test location and a small group of active Interchange members.
Test Discord `/ask` and a Teams personal chat first, then channel mentions. Add
WhatsApp after Meta approves the business and phone number because WhatsApp is
reply-only.

## Slack setup

1. On the Listing page, open the **Distribution → Slack** tab and select
   **Install in Slack**. (A buyer account opens **Settings → Messaging apps**
   directly.)
2. In the new tab, choose the Slack workspace and approve the requested access.
3. Finish authorization in Slack. Interchange does not show the installation
   result yet, so a completed Slack confirmation is the source of truth.
4. Message Murph directly, or add it to an approved channel and mention it.
   Access to account data still depends on the person's active Interchange
   membership and the channel's approved account binding.

This shared Slack app is separate from the incoming webhook used for account
notifications. Authorizing Murph does not configure the notification webhook or
its event filters.

## Microsoft Teams setup

1. Your Microsoft 365 administrator creates or approves the Microsoft Entra
   application and Azure Bot registration for the branded app. The Bot's
   messaging endpoint is the HTTPS endpoint supplied during Interchange
   provisioning.
2. Scope3 generates a Teams app package bound to that exact application ID.
   Review its display name, descriptions, publisher links, accent color, and
   192 px color and 32 px outline icons.
3. Your administrator uploads the package for a pilot or approves it through
   the organization's Teams app policy. Marketplace publication is optional
   for a controlled pilot.
4. Install the app in each approved personal, team, or channel location. Team
   and channel installation does not by itself grant Interchange access.
5. Link each Microsoft Teams user to an active member of the same Interchange
   account. An unlinked person receives a link-account prompt and no account
   data.
6. Test a personal message, then mention the app in an approved channel. A
   channel message that does not mention the app is ignored.

The runtime validates the Microsoft bearer token, issuer, and exact app
audience before reading a message. The app does not accept an email address or
UPN as a destination for a notification. A proactive message, when enabled,
can go only to a conversation captured from an active installation.

<Info>
  The initial Teams package requests `personal` and `team` bot scopes. Group
  chat remains disabled until its separate installation lifecycle is supported.
  These scopes identify an install location; they do not replace Interchange
  membership or identity linking.
</Info>

## Discord setup

1. Create or approve the client's Discord application and branded bot in the
   Discord Developer Portal.
2. On the Listing page, open the **Distribution → Discord** tab (or the **+
   Add destination** picker if the account is not yet in early access) and
   select **Set up in Settings**. (A buyer account opens **Settings →
   Messaging apps** directly.) Then open **Discord → Add a branded app**.
   Enter the application's ID, public key, bot token, display name,
   description, and legal links. Copy the interaction endpoint that
   Interchange returns into Discord's **Interactions Endpoint URL** field.
   Leave **Linked Roles Verification URL** empty.
3. In the Discord Developer Portal, configure the interaction endpoint,
   Guild/User Install settings, and exact global `/ask` command on the matching
   application.
4. Choose user installation, server installation, or both. For a server
   install, approve only the servers and channels where the agent should be
   used.
5. Register each approved install location in the secure setup pane, then link
   each Discord user to an active member of the same Interchange account.
6. Run `/ask question:...` in an approved direct or server context. The app
   acknowledges the command immediately and edits that response when the
   agent finishes.
7. In an approved server channel, mention the installed bot and add the
   question. Only explicit mentions are accepted; unrelated channel messages
   are ignored before account lookup.

The app uses signed HTTP interactions for commands and a singleton Gateway
worker for explicit server mentions. It does not read general server chat or
request Discord's Message Content privileged intent. A bot token is needed for
the Gateway and durable app-initiated delivery and is stored as a secret, never
in the app definition returned to an administrator.

## WhatsApp setup

1. In Meta Business Manager, complete the business, display-name, app, WhatsApp
   Business Account, and phone-number steps required for production Cloud API
   access.
2. Provision the exact Meta app, WhatsApp Business Account, and registered
   phone-number IDs with Interchange. Enter the app secret, system-user access
   token, and a unique webhook verification token only in the secure flow.
3. Configure the supplied HTTPS callback in the Meta app using the same
   verification token and subscribe the app to the WABA `messages` field.
4. Link each WhatsApp user ID to an active member of the same Interchange
   account.
5. From that phone, send a current text message to the registered business
   number and verify that the reply arrives in the same conversation.

WhatsApp is intentionally reply-only. Interchange does not expose template
messages, scheduled messages, broadcasts, arbitrary recipients, or proactive
notifications on this channel. Status events and non-text messages are
acknowledged but do not invoke the agent. If the user-initiated service window
has closed before the answer is ready, the service does not send it.

## Approvals and secure forms

When an agent proposes a governed change, Teams shows **Approve** and
**Cancel** actions in an Adaptive Card and Discord shows equivalent buttons.
Only the linked person who requested the change can use those controls, in the
same provider conversation and before the confirmation expires. A control is
single-use; removing the person's membership, identity link, installation, or
app access also makes a pending control unavailable.

WhatsApp does not receive interactive approval controls. The agent instead
asks for the exact typed confirmation in the active user-initiated conversation.
This remains a synchronous reply path and does not enable later notifications.

Never paste passwords, API tokens, access keys, or other credentials into any
of these chats. Teams and Discord provide a link action to the scoped secure
credential form when one is needed. WhatsApp returns the same HTTPS handoff as
text. Submit the form outside the provider transcript, then reply `done` in the
conversation to continue.

## Permissions and safety

Provider installation proves where the app is installed; it does not prove
who the sender is inside Interchange. Every sender must be explicitly linked
to a current account member. Removing that membership, identity link, or
installation stops new agent turns at that boundary.

Credentials are encrypted and never returned by the provisioning API. Raw
provider user, tenant, channel, server, and phone identifiers are not used as
Interchange authorization. Provider events are authenticated and deduplicated
before the agent runs.

## Settings and API reference

The `/api/v2/messaging-apps` routes below are the public account REST surface
behind the secure setup pane (**Settings → Messaging apps**, reached from the
Listing page's Distribution tabs for seller accounts). They provision
customer-owned apps, install locations, credentials, and identity links. They
are separate from the provider-facing webhook endpoints returned during
provisioning.

Every account endpoint requires a directly authenticated, active administrator
from a human WorkOS-backed Interchange session and an account enrolled in the
messaging-apps pilot, with one exception: [checking shared Slack
availability](#check-shared-slack-availability) is not pilot-gated. API keys,
service tokens, simulated sessions, staff impersonation, and a linked provider
identity are not administrator credentials for this surface. Requests are
scoped to the administrator's authenticated account; `definitionId` and
`installationId` are UUIDs. An account that is not enrolled receives
`FEATURE_NOT_ENABLED` (HTTP 403), which is an availability result rather than
an empty app list.

Provider and Interchange authentication stay distinct:

| Boundary                         | Authentication contract                                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Account REST routes              | Human WorkOS-backed Interchange session, current active administrator membership, and pilot enrollment. Do not call these routes with an Interchange API key or provider token.                                                                                                                                                                                                                                       |
| Discord interactions and Gateway | Discord HTTP requests must have a valid Ed25519 signature for the definition's required public key. The required bot token is verified against the exact application and powers the Gateway and installed-app delivery. The Gateway requests only `GUILDS` and `GUILD_MESSAGES`; Discord's direct-message and explicit-mention exceptions provide the admitted content without the privileged Message Content intent. |
| Microsoft Teams activities       | Microsoft bearer tokens must have the expected issuer and the definition's exact application ID as audience. The required client secret and application-tenant setting belong to that same Azure Bot registration.                                                                                                                                                                                                    |
| WhatsApp callbacks and replies   | Webhook verification uses the required verify token; event delivery must have a valid `X-Hub-Signature-256` for the required app secret. The required system-user access token is used only for Cloud API replies. WhatsApp remains reply-only inside the current user-initiated service window.                                                                                                                      |

Provider credentials are supplied only in create or rotation request bodies,
encrypted at rest, and never returned. The webhook paths do not accept an
Interchange administrator session as a substitute for provider authentication.

### Inspect configured apps

`GET /api/v2/messaging-apps/discord`, `GET /api/v2/messaging-apps/teams`, and
`GET /api/v2/messaging-apps/whatsapp` each return `{ definitions: [...] }` for one
provider. The result is sanitized: it never contains provider credentials, raw
provider actor IDs or their digests, message content, or webhook payloads.

| Response field                         | Meaning                                                                                                                                                                                                                                                                                                                                                                               |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `definitions[].definition.id`          | App-definition UUID.                                                                                                                                                                                                                                                                                                                                                                  |
| `definitions[].definition.customerId`  | Owning Interchange account ID.                                                                                                                                                                                                                                                                                                                                                        |
| `definitions[].definition.agentKey`    | Agent configured for the app.                                                                                                                                                                                                                                                                                                                                                         |
| `definitions[].definition.brand`       | App identity: required `displayName`, `supportUrl`, and `privacyPolicyUrl`; optional `shortDescription`, six-digit `accentColor`, `iconAssetId`, and `termsUrl`. Legal URLs are HTTPS.                                                                                                                                                                                                |
| `definitions[].definition.providerRef` | Provider registration reference. Discord and Teams return `provider` and `applicationId`; WhatsApp returns `provider`, `businessAccountId`, and `phoneNumberId`.                                                                                                                                                                                                                      |
| `definitions[].definition.status`      | `draft`, `active`, or `retired`.                                                                                                                                                                                                                                                                                                                                                      |
| `definitions[].credentialConfigured`   | Whether the required provider credentials are present; credentials themselves are never returned.                                                                                                                                                                                                                                                                                     |
| `definitions[].installations[]`        | Approved provider locations for this definition.                                                                                                                                                                                                                                                                                                                                      |
| `installations[].installation`         | Installation UUID, parent `appDefinitionId`, `customerId`, provider-specific `providerRef`, `status` (`active`, `suspended`, or `uninstalled`), and `installedAt`. Discord references `installContext` (`guild` or `user`) and `ownerId`; Teams references `tenantId` and a `personal`, `team`, or `channel` location; WhatsApp references its business-account and phone-number IDs. |
| `installations[].credentialConfigured` | Whether the installation can use the definition's required credentials.                                                                                                                                                                                                                                                                                                               |
| `installations[].identityBindings[]`   | The linked Interchange person: opaque `bindingId` (used to revoke that exact link), `userId`, `userEmail`, `userName`, `linkedByUserId`, nullable `permissionLevel`, `membershipActive`, `status` (`active` or `revoked`), `verifiedAt`, and nullable `revokedAt`. This intentionally identifies the Interchange membership, not the provider actor ID.                               |
| `installations[].conversationBindings` | Content-free conversation counts: `total`, `direct`, `channel`, and nullable `lastBoundAt`.                                                                                                                                                                                                                                                                                           |
| `installations[].inboundReceipts`      | Content-free inbound counts: `received`, `processing`, `completed`, `ignored`, `failed`, and nullable `lastReceivedAt`.                                                                                                                                                                                                                                                               |
| `definitions[].interactionEndpoint`    | Discord-only HTTPS path to configure in the Discord Developer Portal.                                                                                                                                                                                                                                                                                                                 |
| `definitions[].messagingEndpoint`      | Teams-only HTTPS messaging endpoint.                                                                                                                                                                                                                                                                                                                                                  |
| `definitions[].webhookEndpoint`        | WhatsApp-only HTTPS callback endpoint.                                                                                                                                                                                                                                                                                                                                                |

### Create an app definition

Use `POST /api/v2/messaging-apps/discord`, `POST /api/v2/messaging-apps/teams`, or
`POST /api/v2/messaging-apps/whatsapp`. Each response returns `definition` (the
sanitized definition above) and the provider-specific endpoint
(`interactionEndpoint`, `messagingEndpoint`, or `webhookEndpoint`). The request
body is strict: do not send fields for another provider.

| Endpoint                               | Required provider fields                                                                                                                                                                                                                  |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /api/v2/messaging-apps/discord`  | `applicationId` (15–22 digit Discord ID), 64-character hexadecimal `publicKey`, and `botToken` (32–2,048 characters).                                                                                                                     |
| `POST /api/v2/messaging-apps/teams`    | UUID `applicationId`, UUID `applicationTenantId` or `organizations`, and `clientSecret` (16–4,096 characters).                                                                                                                            |
| `POST /api/v2/messaging-apps/whatsapp` | Numeric `businessAccountId` and `phoneNumberId` (6–32 digits), `appSecret` (16–4,096 characters), `accessToken` (32–8,192 characters), `webhookVerifyToken` (32–512 characters), and a `graphApiVersion` such as `v24.0`.                 |
| Every create request                   | `brand`: required non-empty `displayName` (up to 80 characters), `supportUrl`, and `privacyPolicyUrl`; optional `shortDescription` (up to 200 characters), `accentColor` (`#RRGGBB`), `iconAssetId`, and `termsUrl`. URLs must use HTTPS. |

Provider secrets are accepted only in the request, encrypted, and never
returned by any endpoint. Replacing an app definition does not make a shared
marketplace app; each definition is the customer's own provider registration.

### Register and manage locations

After configuring the endpoint with the provider, register each permitted
location with one of the following strict request bodies. Each successful
registration returns `{ installation }`, using the installation fields in the
inspection table above.

| Endpoint                                                                     | Request fields                                                                                                                                                               |
| ---------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `POST /api/v2/messaging-apps/{definitionId}/discord-installations`           | `installContext` (`guild` or `user`) and 15–22 digit Discord `ownerId`.                                                                                                      |
| `POST /api/v2/messaging-apps/{definitionId}/teams-installations`             | UUID `tenantId` and `location`: `{ kind: "personal", userId }`, `{ kind: "team", teamId }`, or `{ kind: "channel", teamId, channelId }`. Each ID is a non-empty provider ID. |
| `POST /api/v2/messaging-apps/{definitionId}/whatsapp-installations`          | `{}`. The definition's registered business number is the one permitted location.                                                                                             |
| `PATCH /api/v2/messaging-apps/{definitionId}/installations/{installationId}` | `{ status: "suspended" }` to stop new work while retaining the record, or `{ status: "uninstalled" }` to remove the location. Returns `{ installation }`.                    |

Suspending or uninstalling a location stops new inbound work and revokes saved
proactive targets. A Teams removal event also suspends its matching installation
automatically; the control does not depend on a provider token continuing to
work after removal.

### Link or revoke a person

`PUT /api/v2/messaging-apps/{definitionId}/installations/{installationId}/identity`
links one provider actor to an active member of the authenticated account. Send
the strict body `{ externalActorId, userId }`, where `externalActorId` is the
trimmed provider user ID (1–255 characters) and `userId` is a positive
Interchange member ID. It returns `{ linked: true, userId }`.

The secure setup pane lists each linked Interchange person, email, membership
state, and link status so an administrator can audit who has access. It
deliberately does not display the raw provider user ID: that identifier is not needed for
routine access review and must not be exposed through a diagnostic response.
Each audited link instead carries an opaque `bindingId`. To remove that exact
mapping, send `DELETE /api/v2/messaging-apps/{definitionId}/installations/{installationId}/identity`
with `{ bindingId }`; the server scopes the handle again to the authenticated
account, definition, installation, and provider before revoking it. Clients
that do not have the audit response may continue to send `{ externalActorId }`
instead. Send exactly one selector. The response is `{ revoked: boolean }`; the
next provider interaction fails closed before the agent runs.

### Rotate credentials or retire an app

The secure setup pane offers both controls directly on each branded app:
**Rotate credentials** opens the same credential fields used at setup (never
prefilled — the pane never displays an existing secret), and **Retire app**
asks for confirmation before it stops the app for good. Both need an account
administrator; the REST calls behind them are:

`PUT /api/v2/messaging-apps/{definitionId}/credentials` replaces credentials and
returns `{ definition, rotated: true }`. Its strict body declares `provider`
and only that provider's credential fields:

| Provider   | Credential request fields                                                                                                                                |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `discord`  | 64-character hexadecimal `publicKey` and `botToken` (32–2,048 characters).                                                                               |
| `teams`    | UUID `applicationTenantId` or `organizations`, plus `clientSecret` (16–4,096 characters).                                                                |
| `whatsapp` | `appSecret` (16–4,096 characters), `accessToken` (32–8,192 characters), `webhookVerifyToken` (32–512 characters), and `graphApiVersion` such as `v24.0`. |

To retire the entire app, send `PATCH /api/v2/messaging-apps/{definitionId}` with
`{ status: "retired" }`. It returns `{ definition }`. Retirement prevents new
work for the app; use the location controls when only one provider location
should stop.

### Pause an active app

The pilot enrollment flag makes the secure setup pane and the account API
available; it is not a runtime stop for an app that is already installed. Keep
the account enrolled while an administrator applies a lifecycle control.

* To stop one location, suspend its installation in the secure setup pane, or
  send `PATCH /api/v2/messaging-apps/{definitionId}/installations/{installationId}`
  with `{ status: "suspended" }`. New inbound work stops at that location and
  its saved proactive targets are revoked.
* To stop every location for a branded app, select **Retire app** in the
  secure setup pane and confirm, or send
  `PATCH /api/v2/messaging-apps/{definitionId}` with `{ status: "retired" }`.
  New work for that definition stops and its credentials are queued for cleanup.

After either action, refresh the provider list and confirm the expected
`suspended`, `uninstalled`, or `retired` state. If an account was removed from
the pilot before this action, an administrator must have its enrollment restored
first so that they can apply the lifecycle control. Do not remove provider
credentials as an emergency stop; use the audited lifecycle controls.

### Check shared Slack availability

`GET /api/v2/messaging-apps/slack` returns `{ available: boolean, installUrl:
string | null }` for the shared Interchange Slack app described in [Open
messaging destinations](#open-messaging-destinations). Unlike every other
endpoint on this page, it does not require the account to be enrolled in the
messaging-apps pilot: the shared Slack app is not a pilot feature, so any
authenticated member of the account can read whether it can be installed right
now. `available` is `true`, with `installUrl` set, only once Interchange's
shared Slack app is publicly available; otherwise `installUrl` is `null` and
the secure setup pane shows **Coming soon** instead of a working link.

## Pilot acceptance checklist

* Branding and legal links match the client and have provider approval where
  required.
* An account administrator has approved every installation and identity link.
* An unlinked user cannot retrieve account data.
* A linked user can complete at least two turns in the same conversation.
* After 24 hours without a message, the linked user's next message starts a
  new Murph conversation without messages or files from the expired context.
* In a branded Discord, Teams, or WhatsApp app, `/reset` starts a new Murph
  conversation for that linked person. The next turn has no messages or files
  from the previous conversation, while another member's context is unchanged.
* Teams channel messages work only when the app is mentioned.
* Discord works through `/ask` and explicit guild-channel mentions without
  access to unrelated message content.
* Teams and Discord approvals can be used once only by the linked requester in
  the original conversation; another user or location is rejected.
* A credential request opens the scoped secure form and never asks for a secret
  in the provider transcript.
* WhatsApp replies only to a current inbound text from the same person and
  never initiates a conversation.
* Removing an identity or installation prevents later use.

For a failed pilot, record the provider, branded app name, install location,
approximate UTC time, and the safe error shown to the user. Do not include
tokens, secrets, raw webhook payloads, or personal message content.

## Provider references

* [Microsoft Teams app packages](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/build-and-test/apps-package)
* [Microsoft Teams proactive messaging](https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/conversations/send-proactive-messages)
* [Microsoft Teams card actions](https://learn.microsoft.com/en-us/microsoftteams/platform/task-modules-and-cards/cards/cards-actions)
* [Discord interactions](https://docs.discord.com/developers/interactions/receiving-and-responding)
* [Discord user-installable apps](https://docs.discord.com/developers/tutorials/developing-a-user-installable-app)
* [WhatsApp Business Platform](https://www.postman.com/meta/whatsapp-business-platform/overview/)
