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

# manage_collab_partners

> Add, list, remove or invite the partners on one of your collabs.

> [!WARNING]
>
> Writes to your heyBTW workspace on `add` and `remove`. `action: "invite"` SENDS: it emails one partner contact the collab co-host invitation, only after a preview and the user's explicit confirmation. `action: "status"` only reads. Nothing is ever deleted, and nothing is written to the event platform.

A partner is a COMPANY, identified by its domain. Reach for this tool to fill the `partners` gap every import names, or when the user asks who co-hosts an event.

Follows the [heyBTW MCP rules](https://heybtw.com/docs/mcp/rules.md).

## When to use it

* "Who are the partners on the SF dinner?"
* "Marlowe Cloud is co-hosting, add them."
* "Invite Dana at Marlowe so she can see the guest list."
* "Take Acme off the summit."

## Parameters

| Parameter | Type | Used by | Notes |
| - | - | - | - |
| `action` | string | all | Required: `add`, `invite`, `status` or `remove`. |
| `channel_id` | string | all | A collab this workspace owns, from list\_events. |
| `domain` | string | add, remove, invite | The partner company's domain, for example `acme.com`. At most 255 characters. |
| `member_email` | string | add | A business address of a person there, whose domain is used. With `domain`, both must name the same company. |
| `contact_email` | string | invite | The person to email. Must be at the partner's domain. |
| `contact_name` | string | invite | Optional, at most 200 characters. |
| `message` | string | invite | Optional, at most 2,000 characters. |
| `confirm` | boolean | invite | `false` (default) previews; `true` sends. |
| `preview_token` | string | invite confirm | From the preview, valid 15 minutes. |
| `client_request_id` | string | add, remove, invite confirm | A fresh hyphenated UUID. Optional on add and remove. Refused on status and on an invite preview. |
| `contract_version` | string | all | Omit for v1, the only version advertised. |

Arguments an action does not use are refused (`invalid_parameter`, naming each one), never ignored.

## Workflow

### add

Pass `domain` or `member_email`. A company name alone is refused, so ask the user for the domain. The workspace's own domain and personal addresses (gmail.com and the like) are refused. It takes effect at once, like the dashboard's Add Partner: no approval step, no invite sent, no tier, contact or sharing setting changed. When a heyBTW workspace already holds the partner's domain, that workspace is linked to the collab at once (it sees it under the host's Sponsor Mode view). `outcome`: `created`, `reactivated` or `already_present`.

### remove

Pass `domain`. It archives the partner's row, which ends that company's access to THIS collab at once. Nothing is deleted; adding the domain again reactivates it. The host row cannot be removed. `outcome`: `removed` or `already_removed`, with `removed_count`.

With a `client_request_id`, a retry with the SAME id returns the first answer (`idempotent_replay: true`) and changes nothing again; the same id with a different partner, collab or action is refused.

### invite: preview, then explicit confirmation

**1. Preview (sends nothing)**

`action: "invite"`, `confirm: false`, the partner's `domain`, the `contact_email`, and optionally `contact_name` and `message`. The answer is a preview with a `preview_token`, valid 15 minutes.

**2. Get the user's explicit go-ahead**

Show who will be emailed, for which collab, the message, and what the partner will see after accepting (`partner_side_view`). Do not send without a clear yes.

**3. Confirm (sends one email)**

Call again with `confirm: true`, the SAME arguments, that `preview_token` and a fresh `client_request_id`.

If a confirm fails with `send_outcome_unknown` or a retryable error, retry with the SAME `client_request_id`: a confirm that went through is replayed (`idempotent_replay: true`) and never sent twice. Never mint a new id for a retry. If unsure, read `action: "status"` first: once it went through, the partner's `invited_contact` names that contact. If a confirm answers `invite_recorded: false`, the email was sent but heyBTW could not record it. Do not send it again.

A removed partner cannot be invited (add it again first), and the host row cannot be invited.

## Response

### status

| Field | Meaning |
| - | - |
| `domain`, `name` | The partner company. The host row comes first. |
| `partner_type` | As recorded, or null. |
| `status` | `associated`, `invited` or `removed`. |
| `invited_contact` | `{name, email, invited_at}`, or null until an invite was sent. |

`joined` is NOT a state. heyBTW does not record when an invited contact accepts, so an accepted or declined invite shows as `associated` with `invited_contact` set. Never tell the user a partner joined.

Trimmed from a real `status` call today on a ScaleUp.ai fixture collab:

```json theme={null}
{
  "tool": "manage_collab_partners",
  "result_count": 2,
  "data": [
    {"domain": "heybtw.com", "name": "Heybtw", "partner_type": null, "status": "associated", "invited_contact": null},
    {"domain": "marlowecloud.com", "name": "Marlowecloud", "partner_type": null, "status": "associated", "invited_contact": null}
  ],
  "metadata": {
    "coverage_notes": [
      "The states are associated, invited and removed. joined is not reported because heyBTW does not record when an invited contact accepts, so an accepted or declined invite shows as associated with invited_contact set."
    ],
    "contract_version": "v1"
  },
  "status": "ok",
  "gaps": []
}
```

### add, remove and invite

These shapes are from the contract and the code (`tools/manage_collab_partners.py`, `collab-partners-contract.json`). They were not called live, because each writes or sends.

| Action | `data[0]` fields |
| - | - |
| add | `outcome`, `idempotent_replay`, `partner` |
| remove | `outcome`, `removed_count`, `idempotent_replay`, `partner` |
| invite preview | `phase: "preview"`, `preview_token`, `expires_at`, `collab {name, start_date}`, `partner {name, domain}`, `contact {name, email}`, `message`, `consent_will_reset`, `previous_invite` (`{email, invited_at}` or null), `partner_side_view {available_after: "acceptance", tier, visible_columns}` |
| invite confirm | `phase: "confirm"`, `idempotent_replay`, `sent_at`, `invite_recorded`, `contact`, `partner` |

## Rules the agent must follow

* Never send an invite without a preview and the user's explicit go-ahead. An invite emails one person.
* Never retry a confirm with a new `client_request_id`. Read `status` when unsure.
* Never say a partner joined.
* Ask for a domain; never guess one from a company name.
* This tool never sets a partner's tier, mode or contact (other than an invite's) and never deletes anything.

## Errors and gaps

| Code | What to do |
| - | - |
| `invalid_parameter` | Fix each named parameter. With no `action`, it asks for one of add, invite, status, remove. |
| `entity_not_found` | A partner's collab, the demo collab or an unknown id. |
| `send_outcome_unknown` | Retry the confirm with the SAME `client_request_id`, or read `status`. |
| `insufficient_scope` | The OAuth token lacks `mcp:tools:write` (needed for add, remove, invite; not for status). Nothing changed. |
| 429 | Honor `Retry-After`. 30 requests per 5 s, 60 per minute, 1000 per day per workspace. |

## Related

* [get\_event\_details](https://heybtw.com/docs/tools/get-event-details.md), which also lists each partner's status
* [record\_signups](https://heybtw.com/docs/tools/record-signups.md) and [create\_collab](https://heybtw.com/docs/tools/create-collab.md), whose `import_gaps` point here
* [get\_partner\_insights](https://heybtw.com/docs/tools/get-partner-insights.md)
* Playbook: [Connect heyBTW next to your CRM and your event platform](https://heybtw.com/docs/playbooks/connect-crm-and-event-platform.md)


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