# Partner Management with AI (MCP)

Work your partner program from an AI assistant: the PRM tools of the Fours MCP server, what each one needs, and four worked examples

---

## Overview

The [Fours MCP Server](/mcp/overview/) exposes Partner Management (PRM) as tools that any
[Model Context Protocol](https://modelcontextprotocol.io/) client can call — Claude Desktop, Claude
Code, ChatGPT, Cursor, VS Code (GitHub Copilot) and others. An assistant connected to it can look up
partners and their contacts, check journey and training progress, work partnership tasks, keep
agreements and events up to date, and send or answer partnership invitations, all in plain language.

**Availability:** Organizations with Partner Management

**MCP Server URL:** `https://apiv2.suger.cloud/mcp`

To connect a client, see [Connect an AI Assistant](/mcp/setup/). For the full catalog across every
area, see [Supported Tools](/mcp/tools/). Deal registration and partner co-sells run on the co-sell
tools; see [Co-Sell with AI (MCP)](/cosell/ai/mcp/) and the
[deal-registration example](#register-a-deal-a-partner-raised) below.

## How access works

Each tool below lists two requirements.

**Access** says whether the tool only reads (`read`) or changes something (`write`). An assistant
you connect yourself gets both kinds; an assistant that confirms changes before making them asks you
before every `write` tool. Fours AI, the assistant in the Fours Console, is the one exception: its own
connection to this server has an **Access** setting under **Settings › Integrations › Custom MCP
Servers**. **Read only** (the default) gives it only the `read` tools, and **Read & write** adds the
`write` tools. See [MCP](/integrations/mcp/).

**Permission** is the Fours permission the call is checked against, every time, whoever makes it —
the same permission the Fours Console needs for that action. Your role decides which you hold (see
[Who can use Partner Management](/prm/#who-can-use-partner-management)). If you chose **Custom** for
an organization when you approved the client's access, the assistant holds only the permissions you
ticked there: the `partners.*` permissions are listed under **Sales & Cosell**, and `crm.read_record`
under **Customers & Buyers**.

Three more things to know before you prompt:

- **Training and Commissions can be switched off.** The training tools need **Training**, and
  `GetPartnerCommissions` needs **Commissions**, switched on under **Partners → Settings → Features**.
  See [Navigate the Partner Console](/prm/navigate-the-partner-console/).
- **IDs come from the list tools.** `partnerId` and `partnershipId` are both a partnership's `id`
  from `ListPrmPartners`. `partnerOrgId` is a different value: the partner's own Fours organization,
  carried on the same record as `partnerOrgId`.
- **Lists come one page at a time.** Each list tool returns 10 rows per call unless you set `limit`
  (up to 100, or 200 for journeys, tasks and task templates). Ask the assistant to page by sending `limit` on every call, with `offset`
  a multiple of it (0, `limit`, twice `limit`, ...), until it has `total_count` rows. An `offset`
  sent without `limit`, or one that is not a multiple of it, returns the wrong rows without an error.
  Most list tools also take `q`, a filter over the record's stored fields written as
  `(= status "BLOCKED")` and combined with `(and ...)`, and `s`, a sort field (prefix `-` for
  descending). Values a list computes, such as a journey's `stalled` flag or `partnerName`, cannot be
  filtered with `q`; use the tool's own parameters, such as `statuses` and `search`.

## PRM tools

The MCP server exposes 45 PRM tools: 28 that read and 17 that write.

### Partners and contacts

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPrmPartners` | List the partner companies you have a relationship with | `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GetPrmPartnerDetail` | Get the full record for one partnership, including the partner-portal view | `partnerId` | `read` | `partners.read` |
| `UpdatePrmPartner` | Change a partnership's manager, status, partner types or profile | `partnerId`, `partnerManager`, `status`, `partnerTypes` | `write` | `partners.edit` |
| `GetPrmPartnerContacts` | List the people at one partner; with `scope=all`, the partner record's whole **Relationship Hub** contact list | `partnerId`, `scope`, `q`, `role`, `source`, `syncStatus` | `read` | `partners.read` |
| `ListPrmPartnerCrmContacts` | List the contacts on the Salesforce Account or HubSpot Company linked to one partnership | `partnerId` | `read` | `partners.read` and `crm.read_record` |
| `CreatePrmPartnerHubContact` | Add a person to a partner's **Relationship Hub** contact list | `partnerId`, `firstName`, `lastName`, `email`, `title`, `role`, `createInCrm` | `write` | `partners.edit` |
| `UpdatePrmPartnerHubContact` | Edit a person on a partner's **Relationship Hub** contact list | `partnerId`, `contactId`, the fields to change, `syncToCrm` | `write` | `partners.edit` |
| `GetPartnerCommissions` | Get one partner's commission ledger: each closed-won deal, plus totals per currency | `partnerId` | `read` | `partners.read` |

`CreatePrmPartnerHubContact` refuses an email address already on the list with a `409`. With
`createInCrm`, the new contact is also created on the partnership's linked Salesforce Account in the
background, and the outcome shows on the contact; with no linked Salesforce Account it is saved in
Fours only. With `syncToCrm`, an edit pushes the contact's name and title (never its phone or
LinkedIn) to the Salesforce contact. The email of a contact that is already in your CRM cannot be
changed, because the CRM record is matched by it: such an edit is refused and nothing in it is
saved. To edit a contact, pass its `id` from `GetPrmPartnerContacts` with `scope=all`. See
[Work a Partner Record](/prm/work-a-partner-record/#contacts).

### Invitations

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPrmOrgInvitations` | List every partnership invitation your organization sent or received | `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `ListPrmInvitations` | List the invitations attached to one partnership | `partnerId`, `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `ListPrmInvitationLinkableFiles` | List the files you can link from an invitation email | `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GeneratePrmInvitationEmail` | Draft the subject and body of an invitation email; sends nothing | `partnerId` or `partnerName`, `purpose`, `tone`, `referencedDocuments` | `read` | `partners.edit` |
| `CreatePrmInvitation` | Invite a person to an existing partnership, and try to email them | `partnerId`, `recipientEmail`, `recipientName`, `messageSubject`, `messageBody` | `write` | `partners.create` |
| `CreatePrmNewPartnerInvitation` | Invite a company you have no partnership with yet, and try to email them | `recipientEmail`, `recipientName`, `newPartner`, `messageSubject`, `messageBody` | `write` | `partners.create` |
| `ResendPrmInvitation` | Extend the accept-by date of an invitation you sent, and try to email it again | `invitationId` | `write` | `partners.edit` |
| `CancelPrmInvitation` | Withdraw an invitation you sent | `invitationId` | `write` | `partners.edit` |
| `AcceptPrmInAppInvitation` | Accept an invitation another company sent you | `invitationId` | `write` | `partners.edit` |
| `DeclinePrmInAppInvitation` | Decline an invitation another company sent you | `invitationId` | `write` | `partners.edit` |

`GeneratePrmInvitationEmail` sends and saves nothing, so it is a `read` tool although it is a `POST`;
it still needs `partners.edit`, and it calls a language model, so each draft records AI usage for your organization. An invitation is saved
even when its email fails: check `emailSent` on a resend and `info.outbound.emailDelivery.status` on
a new invitation before reporting it as sent. See [Supported Tools](/mcp/tools/) and
[Invite Partners](/prm/invite-partners/).

### Journeys

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListJourneyAssignments` | List the journeys assigned to your partners, each with its steps and their due dates, plus organization-wide `totals` (active, completed, stalled) | `statuses`, `partnerId`, `templateId`, `search`, `includeArchived`, `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GetJourneyAssignment` | Get one assigned journey with its steps, progress and `stalled` flag | `assignmentId` | `read` | `partners.read` |
| `AssignJourney` | Assign a journey template to a partner | `partnerId`, `templateId` | `write` | `partners.create` |
| `TransitionJourneyStep` | Mark a step done, or reopen it | `assignmentId`, `stepId`, `to` (`DONE`, `IN_PROGRESS`, `NOT_STARTED`) | `write` | `partners.edit` |

Journey templates are part of your program settings: read them, and the default onboarding
template, with `GetPrmPartnershipConfigs` (under [Program](#program)). Only an `ACTIVE` template can
be assigned, only to a partnership where you are the seller, and not to a partner that has had it
before, even if that journey was completed or archived. Assigning does what the **Assign** button
does: steps with a relative due date get their dates from the assignment date, a task is created
for each custom-task step, a **Sign agreement** step creates its agreement at `AWAITING_SIGNATURE`,
and an email goes to you and to the partner's champion contact. Undoing an assignment (archiving
it) is done in the Fours Console; no tool does it. See
[Create and Assign Partner Journeys](/prm/create-and-assign-journeys/).

`ListJourneyAssignments` also lists journeys that another company assigned to you as its partner,
and `totals` counts them; on those rows `organizationId` is not yours. Keep the rows whose
`organizationId` is your organization to report on your own partners.

A journey is **stalled** when it is `ACTIVE` and has not changed for more than seven days; pass
`statuses=STALLED` to list only those. A step is **overdue** when its `status` is not `DONE` and its
`dueAt` has passed. In a sequential journey, a step can be marked done only once the required steps
before it are done. Marking a custom-task step done also updates its linked task, and marking the
last required step done completes the journey and, when the journey has a tier outcome, moves the
partner to that tier. See
[Track Journey Progress](/prm/track-journey-progress/).

### Tasks

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPartnershipTasks` | List the tasks you track with your partners | `q` (for example `(= partnershipId "<id>")` or `(= status "BLOCKED")`), `tab`, `assigneeUserId`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GetPartnershipTask` | Get one task with its subtasks and resources | `taskId` | `read` | `partners.read` |
| `ListPartnershipTaskTemplates` | List your reusable task templates | `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `CreatePartnershipTask` | Create a task on a partnership; it starts `OPEN` | `partnershipId`, `title`, `dueAt`, `priority`, `assignedSide`, `assigneeUserIds` | `write` | `partners.create` |
| `UpdatePartnershipTask` | Change a task's title, description, due date, priority, assignees, subtasks or resources | `taskId`, `version`, the fields to change | `write` | `partners.edit` |
| `TransitionPartnershipTask` | Move a task to `OPEN`, `IN_PROGRESS`, `BLOCKED` or `COMPLETED` | `taskId`, `to`, `version` | `write` | `partners.edit` |

Only the side a task is assigned to can change its status, and on a task the partner shared with
you (`direction` `INBOUND`) you can change only your assignees, resources and, when it is assigned to
you, subtask statuses; anything else is refused with `403 TASK_PARTNER_SIDE_NOT_ALLOWED`.
Both changes to an existing task need the `version` you last read; when someone has changed the task
since, the call is refused with `409 TASK_VERSION_CONFLICT`, so read it again and retry. A status
change goes through `TransitionPartnershipTask`, never `UpdatePartnershipTask`. `subtasks` and
`resources` sent to `UpdatePartnershipTask` replace the whole list, and leaving out a resource the
partner attached is refused. Completing a task that a journey step created also completes that
step. No tool applies a task template in one call: the assistant creates one task per template
entry with `CreatePartnershipTask`.

### Training

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListCourses` | List the courses you authored, or with `tab=from_partners` the courses partners shared with you | `tab`, `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GetCourse` | Get one course: for your own, its draft, its published version or a version number; for a partner's, its published version | `courseId`, `version` | `read` | `partners.read` |
| `ListCourseEnrollments` | List the enrollments in one course, across every partner organization | `courseId` | `read` | `partners.read` |
| `ListOrgCertificates` | List the certificates your own team's users hold from partners' courses | none | `read` | `partners.read` |
| `GetOrgTrainingRollup` | Tally every published course across every partner, by course and by partner (least complete first) | none | `read` | `partners.create` |
| `GetPartnerTrainingSummary` | Tally your published courses for one partner, including courses nobody there has started | `partnerOrgId` | `read` | `partners.create` |

The two tally tools only read, but they are checked against `partners.create`, so a role or a
**Custom** grant with only `partners.read` cannot call them. They return counts, not rates: ask the
assistant to show both numbers behind any percentage. When a course comes from an external learning
platform and `completionSyncEnabled` is false, Fours is not polling that platform for completions,
so a zero there may only mean none were reported. See [Share and Monitor Partner Training Courses](/prm/share-monitor-training/).

### Agreements

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPartnerAgreements` | List partner agreements, newest first, with type, status and dates | `partnershipId`, `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `UpdatePartnerAgreement` | Change an agreement's name, type, status, effective date or expiry date | `agreementId`, `name`, `type`, `status`, `effectiveDate`, `expiryDate`, `version` | `write` | `partners.edit` |

`type` is one of `NDA`, `MSA`, `REFERRAL_AGREEMENT`, `SOW` or `OTHER`, and `status` one of `DRAFT`,
`AWAITING_SIGNATURE`, `PARTIALLY_SIGNED`, `FULLY_EXECUTED` or `EXPIRED`. Fours never detects a
signature, so the status moves only when someone sets it, and only the company that sent the
agreement can set it. Moving an agreement to `FULLY_EXECUTED` marks the journey's **Sign
agreement** step done. Without `partnershipId`, `ListPartnerAgreements` lists only the agreements
you sent; pass `partnershipId` to include those a partner sent you. Dates are full timestamps, such
as `2026-12-31T00:00:00Z`. See
[Work a Partner Record](/prm/work-a-partner-record/#agreements).

### Events

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPartnerEvents` | List the events you run and those shared with you by companies whose partner program you belong to, oldest first, past events included | `q`, `s`, `limit`, `offset` | `read` | `partners.read` |
| `GetPartnerEvent` | Get one event | `eventId` | `read` | `partners.read` |
| `ListPartnerEventRsvps` | List who responded to an event you own | `eventId` | `read` | `partners.read` |
| `CreatePartnerEvent` | Create an event and share it with all partners, specific partners or a tier | `title`, `type`, `startDatetime`, `endDatetime`, `timezone`, `visibilityType`, `shareTargetIds`, `isRsvpEnabled`, `capacity`, `status` | `write` | `partners.create` |
| `UpdatePartnerEvent` | Change an event you own | `eventId`, the fields to change | `write` | `partners.edit` |

`type` is `webinar`, `training`, `in_person` or `general`. For `visibilityType` `specific`, pass
`ACTIVE` partnership ids in `shareTargetIds`; for `tier`, tier ids. Sending `shareTargetIds` on an
update replaces who the event is shared with; when an update changes `visibilityType`, it must send
`shareTargetIds` too, or partners can stop seeing the event. An event is visible to the partners it is shared with as soon
as it is created, whatever its `status`; the Fours Console saves events as `published`, so send the
same. A `cancelled` event no longer takes RSVPs. See [Create and Share Partner Events](/prm/partner-events/).

### Files

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `ListPartnerFiles` | List your partner file library, or with `direction` the files shared with or received from one partner | `q`, `s`, `limit`, `offset`, `direction` (`shared` or `received`), `partnerOrgId` | `read` | `partners.read` |
| `GetPartnerFile` | Get one file, with a link to it that works for one hour | `fileId` | `read` | `partners.read` |

The link from `GetPartnerFile` works even for a file whose sharing settings allow viewing only, so
treat it as you would the file itself.

### Program

| Tool | What it does | Key inputs | Access | Permission |
|------|--------------|------------|--------|------------|
| `GetPrmDashboard` | Get one section of the partner program dashboard: the headline figures and what needs attention | `section` (`overview`, `footprint` or `moneyAdmin`), `channel`, `partnerType`, `tierId`, `myPartnersOnly`, `limit`, `offset` | `read` | `partners.read` |
| `GetPrmPartnershipConfigs` | Get your program settings, including journey templates, the default onboarding template, tiers, registration forms and file-sharing defaults | none | `read` | `partners.read` |

`GetPrmDashboard` reports money per currency, never as one cross-currency total, and its result is
cached: `computedAt` says how old the figures are. See
[Partner Program Dashboard](/prm/partner-program-dashboard/).

### Not available to an assistant

These stay in the Fours Console:

- **Deletes** — removing a partner contact, task, event, agreement or shared file.
- **Course authoring** — creating, editing, publishing and uploading courses, SCORM packages
  included.
- **External learning platform settings** — see [Connect an External LMS](/prm/connect-an-external-lms/).
- **Partner-side actions** — enrolling your own team in a course or reading your own enrollments and
  certificates. These are what a partner does in its portal, not what a seller does for a partner.
- **Broadcasts** — writing, scheduling and sending them.
- **Program setup** — creating an agreement or attaching its files, uploading partner files,
  archiving, resetting or reassigning a journey, and building journey or task templates.

## Worked examples

Each example is a prompt you can give an assistant, followed by the calls it makes.

### Find partners stuck in onboarding

> "Which partners are stuck in onboarding, and which have a journey step overdue?"

1. `ListJourneyAssignments` with `statuses=STALLED`. These are active journeys with no change for
   more than seven days; `totals.stalled` gives the count for the whole organization. To narrow to
   one journey, add `search=Onboarding` (it matches journey names as well as partner names) or the
   template's `templateId`.
2. `ListJourneyAssignments` with `statuses=ACTIVE`, paging with `limit` and `offset` until it has
   `total_count` rows. In each row, any step whose `status` is not `DONE` and whose `dueAt` is before
   today is overdue.
3. The assistant reports each partner by `partnerName`, with the overdue step's `title` and `dueAt`.

If a partner has finished a step outside Fours, follow up with "Mark the kickoff call step done for
Acme Corp": the assistant calls `TransitionJourneyStep` with `to=DONE`, a `write` tool, so it asks
you first.

### Assign a journey to a partner

> "Assign the Onboarding journey to Acme Corp."

1. `GetPrmPartnershipConfigs` — find the journey template named Onboarding in `journeyTemplates`,
   check its `status` is `ACTIVE`, and take its `id`.
2. `ListPrmPartners` — find Acme Corp's partnership and take its `id`.
3. `AssignJourney` with `partnerId` and `templateId`.

The call is refused when the template isn't `ACTIVE`, when Acme Corp already has that journey, or
when you aren't the seller on the partnership. To give the same journey to every new partner
automatically, set a default onboarding template in the console instead; see
[Create and Assign Partner Journeys](/prm/create-and-assign-journeys/#assign-a-journey-automatically-to-every-new-partner).

### Weekly training roll-up

> "Give me this week's partner training roll-up: completion by course, the five partners furthest
> behind, and what each of them hasn't started."

1. `GetOrgTrainingRollup` — `courses` gives enrolled and completed counts per course; `byPartner`
   lists partners least complete first, each with its `partnerOrgId`. `partnerCount` counts only
   partners with at least one enrollment.
2. `GetPartnerTrainingSummary` for each of the first five `partnerOrgId` values — per course, how many
   learners are not started, opened, in progress, completed or failed. Courses nobody at that
   partner has started are included at zero.
3. Optionally, `ListCourseEnrollments` for a course whose numbers look wrong, to see the enrollments
   behind them.

Both tally tools need `partners.create` and **Training** switched on. The MCP server runs nothing on
a schedule: ask each week, or use your client's own scheduling if it has one.

### Register a deal a partner raised

> "Acme Corp brought us a qualified deal with Globex on today's call, worth 120,000 USD and closing
> in March. Register it to Acme, link it to our CRM opportunity, and tell me when its status
> changes."

This example uses co-sell tools, which are checked against the `cosell.*` permissions rather than
`partners.*`. Who is calling decides which tool registers the deal:

```d2
direction: down

start: "A deal a partner raised" { shape: rectangle }
who: "Who is calling\nthe MCP server?" { shape: diamond }
onbehalf: "RegisterCosellOnBehalf\nthe co-sell is ACTIVE at once,\nand the partner's contact is emailed" { shape: rectangle }
draft: "CreateDealRegistrationDraft\nsaved as a draft; a person\nconfirms it in the Fours Console" { shape: rectangle }
crm: "SyncSugerCosellReferral\nupdate the co-sell from its\nlinked CRM opportunity" { shape: rectangle }
watch: "ListNotificationEventsByEntity\nSUGERCOSELL and the referral id" { shape: rectangle }

start -> who
who -> onbehalf: "a person, signed in\nthrough an MCP client"
who -> draft: "an OAuth App,\nno person signed in"
onbehalf -> crm: "if linked to a CRM opportunity"
draft -> crm: "once confirmed and linked"
crm -> watch
```

1. **Find the partner.** `ListPrmPartners` gives Acme Corp's partnership `id`. To choose who at Acme
   is notified and owns the deal there, `GetPrmPartnerContacts` with `scope=all` lists the
   candidates; otherwise the partnership's champion contact is used.
2. **Register the deal.** `RegisterCosellOnBehalf` with `partner` `SUGER`, `partnerId`, and under
   `info.sugerOpportunity` the `type` and `dealDetails` (`name`, `dealValueAmount`,
   `dealValueCurrency`) plus the customer fields your
   [deal registration form](/prm/register-a-deal/#choose-the-fields-of-your-deal-registration-form)
   requires. There is no separate approval: the co-sell is `ACTIVE` at once, Acme Corp's contact is
   emailed that it was registered on their behalf, and your side drives its stage from then on. It
   needs `cosell.create_referral`, and a partnership that is `ACTIVE` (or `PENDING` with an
   invitation outstanding) with you as the seller. Because it contacts the partner, the tool's
   description tells the assistant to confirm the partner and the deal with you first.
   - For a deal your team sourced and is sharing with Acme Corp, the call is
     `CreateSugerCosellReferral` instead; Acme Corp then accepts or declines its copy.
   - To approve a registration a partner submitted itself, which waits in `PENDING_ACCEPTANCE`,
     call `UpdateSugerCosellReferral` with `status` `ACTIVE` and a `team` naming at least one
     owner on your side. It needs `cosell.edit_referral`.
3. **Link the CRM opportunity.** No MCP tool creates an opportunity in your CRM. To link the co-sell
   to an existing Salesforce opportunity or HubSpot deal, call `UpdateSugerCosellReferral` with
   `isLinkageUpdate=true` and the record's id (`salesforceOpportunityId` or `hubspotDealId`), or
   choose it in the console when you register the deal (see
   [Register a Deal with a Partner](/prm/register-a-deal/#step-2-choose-or-skip-a-crm-opportunity)).
   After that, `SyncSugerCosellReferral` with `direction=OUTBOUND` updates the co-sell from the
   opportunity; it needs `cosell.create_referral`.
4. **Watch for changes.** `ListNotificationEventsByEntity` with `entityType` `SUGERCOSELL` and the
   co-sell's referral id lists its events, and needs `notification.read`. `GetSugerCosellReferral`
   returns the co-sell's current status and stage. The MCP server doesn't push
   events to your client, so an automated pipeline asks again on its own schedule.

:::warning
**An OAuth App can't create a co-sell through the MCP server.** When the caller is an
[OAuth App](/settings/oauth-app/) — a service running with no person signed in — `RegisterCosellOnBehalf`
and `CreateSugerCosellReferral` are refused with `AI agents cannot create or resubmit referrals`, and
`UpdateSugerCosellReferral` with `isLinkageUpdate=true` is refused with
`AI agents cannot change a referral's CRM linkage`. Such a service records the deal with
`CreateDealRegistrationDraft` instead, and a person on your team confirms the draft in the console
(see [Track and Respond to Deals](/prm/track-and-respond-to-deals/)). It can still approve a
registration a partner submitted, sync, and watch. A person signed in through an MCP client with
their own login is not affected.
:::

## Troubleshooting

| Issue | Possible cause | Resolution |
|-------|----------------|------------|
| A call is refused for missing permission | Your role lacks the permission the tool lists, or you chose **Custom** for the organization and didn't tick it | Ask an Admin to change your role, or reconnect the client and grant the permission |
| `GetOrgTrainingRollup` or `GetPartnerTrainingSummary` is refused, but other training tools work | These two need `partners.create`, not `partners.read` | Grant `partners.create`, or use a role that holds it |
| Training tools or `GetPartnerCommissions` are refused for the whole organization | **Training** or **Commissions** is switched off | An organization admin switches it on under **Partners → Settings → Features** |
| Fours AI says a tool needs `write` access | Its connection's **Access** is **Read only** | Change it to **Read & write** under **Settings › Integrations › Custom MCP Servers** |
| `AssignJourney` is refused | The template isn't `ACTIVE`, the partner already has that journey, or you aren't the seller on the partnership | Activate the template, check the partner's journeys with `ListJourneyAssignments` and `partnerId`, or assign it from the seller's organization |
| `TransitionJourneyStep` is refused with `step is locked until prior required steps are complete` | The journey is sequential and an earlier required step isn't done | Mark the earlier required steps done first |
| `409 TASK_VERSION_CONFLICT` or `AGREEMENT_VERSION_CONFLICT` | The record changed after the assistant read it | Read it again with `GetPartnershipTask` or `ListPartnerAgreements` and retry with the current `version` |
| `409 TASK_INVALID_TRANSITION` | The task is already in the target status | Nothing to do |
| `403 TASK_PARTNER_SIDE_NOT_ALLOWED` | The task is assigned to the partner's side, or it is a task the partner shared with you and the change is theirs to make | Ask the partner to make the change, or change the task's `assignedSide` from the side that created it |
| `CreatePrmPartnerHubContact` returns `409` | That email address is already on the partner's contact list | Edit the existing contact with `UpdatePrmPartnerHubContact` |
| A list looks short | Only the first page came back | Page with `limit` and `offset` until you have `total_count` rows |
| `AI agents cannot create or resubmit referrals` | The caller is an OAuth App | Record the deal with `CreateDealRegistrationDraft` for a person to confirm, or have a person make the call |

## Security and scope

- **Authentication:** OAuth 2.1 only; API keys and static tokens are not accepted.
- **Organization scoping:** every call is scoped to the organization you authorized; the assistant
  cannot reach another organization's partners.
- **Permissions:** every call is checked against your Fours permissions, as listed for each tool.
  The MCP server never grants more than your account already has.
