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

# Partner attribution in Salesforce

> Every way to attribute Salesforce opportunities to partners - picklists, Account lookup, OpportunityPartner junction, and custom objects - with setup.

export const object_3 = "opportunity"

export const crm_2 = "Salesforce"

export const object_2 = "opportunity"

export const crm_1 = "Salesforce"

export const object_1 = "opportunity"

export const crm_0 = "Salesforce"

export const object_0 = "opportunity"

Attribution is the link between a Salesforce record and the partner who sourced or influenced it. It is what makes partner-attached pipeline, reporting, and commissions trustworthy - so it deserves to match how your org is actually modelled, not the other way around.

Salesforce orgs model that link in four different ways, from a single field to a full junction object. **Introw supports all four out of the box.**

There is no RevOps project, no schema rebuild, no code, and no {crm_0} consultant. You keep your existing model; you simply tell Introw *how a record is linked to a partner*, and from there Introw does the rest:

<CardGroup cols={3}>
  <Card title="Reads it in" icon="arrow-right-to-bracket">
    Introw pulls every matching {object_0}, even old ones, and attributes each correctly.
  </Card>

  <Card title="Embeds it" icon="table-cells">
    Attributed records appear in portals, dashboards, commissions, and reporting under your name.
  </Card>

  <Card title="Writes it back" icon="arrow-right-from-bracket">
    A form submission is attached with the *exact method* you configured, so the record is born compliant.
  </Card>
</CardGroup>

<Note>
  The whole point: **you match your system to Introw once, and Introw matches every record to your system forever.** Historic {object_0}s become attributable, and new partner-created records are born correctly attributed. That is the backwards-compatibility and data-hygiene win - and it holds for whichever method below you already use.
</Note>

## The four methods at a glance

<CardGroup cols={2}>
  <Card title="Picklist field" icon="list">
    A picklist on the Opportunity names the partner. Simplest; no relationships needed.
  </Card>

  <Card title="Lookup to an Account" icon="link">
    A lookup field points the Opportunity at the real partner Account. Clean and reportable.
  </Card>

  <Card title="Relation (junction) table" icon="diagram-project">
    A junction object (e.g. OpportunityPartner) links many partners to one opportunity, with roles.
  </Card>

  <Card title="Custom object" icon="cubes">
    A dedicated Partner object relates to opportunities, accounts, and contacts. Richest data model.
  </Card>
</CardGroup>

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart TB
  subgraph SF["How the link is stored in Salesforce"]
    direction LR
    pk["Picklist field<br/>on Opportunity"]
    lk["Lookup field<br/>to partner Account"]
    jt["Relation table<br/>OpportunityPartner"]
    co["Custom object<br/>Partner"]
  end
  pk --> introw["Introw Object Linking<br/>name it, set eligibility"]
  lk --> introw
  jt --> introw
  co --> introw
  introw --> out["Attributed pipeline, reporting, commissions, portals"]
```

<Note>
  Configure **Opportunity** attribution at minimum - it is what reporting and commissions run on. You can attribute contacts, accounts, cases, and custom objects to partners the same way.
</Note>

***

## Method 1 - Picklist field

**Best for:** simpler programs with one partner per opportunity, and teams that want attribution with no relationships to design.

A **picklist** field on the Opportunity (e.g. "Partner Name") holds a predefined set of partner values reps select from.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
erDiagram
  OPPORTUNITY {
    string Name
    number Amount
    picklist Partner_Name__c "the partner"
  }
  PARTNER_VALUE {
    string label "one value per partner"
  }
  OPPORTUNITY }o--|| PARTNER_VALUE : "value identifies partner"
```

<AccordionGroup>
  <Accordion title="How it works in Salesforce" icon="gear">
    A picklist stores a fixed list of values on the record. Reps choose the partner from the dropdown on the Opportunity. It's the lightest-weight option - no relationship, no junction - and easy to report on with standard Salesforce reports.
  </Accordion>

  <Accordion title="How Introw configures it" icon="sliders">
    Choose **Custom properties** and select the picklist. If the values are coded (IDs or abbreviations rather than partner names), use **Match property values to Introw partners** to line each value up with the right partner record.
  </Accordion>

  <Accordion title="Trade-off" icon="triangle-exclamation">
    A picklist is text, not a relationship - it doesn't point at the real Account, and values can drift if hand-maintained. Great to start; consider a lookup or relation table as the program scales.
  </Accordion>
</AccordionGroup>

| Pros                                      | Cons                                                                 |
| ----------------------------------------- | -------------------------------------------------------------------- |
| Simplest possible setup, no relationships | One partner per picklist - add a picklist per role for multi-partner |
| Standard Salesforce reporting             | Not linked to the real Account record                                |
| Works in any edition                      | Values drift without governance                                      |
| Fast to roll out                          | Coded values need a one-time value-to-partner map                    |

***

## Method 2 - Lookup field to an Account

**Best for:** clean one-to-one attribution where you want to reference the real partner Account and pull its data.

A **lookup relationship** from the Opportunity to the partner **Account** stores the actual partner record, not a text label.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
erDiagram
  ACCOUNT ||--o{ OPPORTUNITY : "Partner_Account__c lookup"
  ACCOUNT {
    string Name
    string Website
    string Type
  }
  OPPORTUNITY {
    string Name
    number Amount
    lookup Partner_Account__c
  }
```

<AccordionGroup>
  <Accordion title="How it works in Salesforce" icon="gear">
    A lookup is a loosely-coupled relationship connecting one object to another. A custom lookup field on the Opportunity (e.g. "Partner Account") points at the partner Account record. Because it references the real Account, you get the partner's data, clean roll-up reporting, and no duplicated names. An object can hold up to 40 relationship fields, so adding a partner lookup is no strain.
  </Accordion>

  <Accordion title="How Introw configures it" icon="sliders">
    Choose **Custom properties** and select the lookup field that points to the partner Account. Introw resolves the lookup to the partner record automatically - no value mapping needed, because the field already references the real Account.
  </Accordion>

  <Accordion title="Using the standard AccountId" icon="link">
    You are not restricted to a custom lookup: the Opportunity's **standard `AccountId`** can be selected as the attribution property too. That fits programs where the Account on the opportunity *is* the partner rather than the end customer - a distributor or reseller model where you sell to the partner and they resell onward. For programs where `AccountId` holds the end customer, keep it as the customer and add a separate partner lookup, so the two are never conflated.
  </Accordion>

  <Accordion title="Multiple partners? Add more lookups" icon="triangle-exclamation">
    A single lookup holds one partner, but you are not limited to one lookup. Add a lookup field per role - "Sourcing Partner", "Delivery Partner", "Implementation Partner" - and map **each as its own named attribution** in Introw, so one opportunity credits several partners across tiers. A relation table (Method 3) is the alternative when the set of partners or roles is open-ended rather than a fixed few.
  </Accordion>
</AccordionGroup>

| Pros                                | Cons                                                             |
| ----------------------------------- | ---------------------------------------------------------------- |
| References the real Account record  | One partner per lookup - add a lookup per role for multi-partner |
| Clean, reportable, no name drift    | Requires the partner to exist as an Account                      |
| Pulls partner data straight through | -                                                                |
| Easy for reps to set                | -                                                                |

<Tip>
  The lookup-to-Account is the recommended default for most Salesforce programs running one partner per deal: it's clean, native, reportable, and Introw reads it with zero mapping.
</Tip>

***

## Method 3 - Relation (junction) table

**Best for:** multiple partners per opportunity, revenue splits, or programs that track the *role* each partner plays.

A **junction object** between Opportunities and partner Accounts creates a true many-to-many relationship. Salesforce even ships one for exactly this: the standard **OpportunityPartner** object, surfaced as the **Partners** related list on the Opportunity.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
erDiagram
  OPPORTUNITY ||--o{ OPPORTUNITY_PARTNER : "has partners"
  ACCOUNT ||--o{ OPPORTUNITY_PARTNER : "is partner on"
  OPPORTUNITY_PARTNER {
    id OpportunityId
    id AccountToId "partner Account"
    string Role "Reseller / Referrer / SI"
    boolean IsPrimary
  }
  OPPORTUNITY {
    string Name
    number Amount
  }
  ACCOUNT {
    string Name
  }
```

<AccordionGroup>
  <Accordion title="How it works in Salesforce" icon="gear">
    A junction object is a child of two parents, connecting them many-to-many. Each row links one opportunity to one partner account, and carries a **Role** (Reseller, Referrer, System Integrator, ...) and an **IsPrimary** flag. So one opportunity can credit several partners at once, each in a distinct role. Salesforce's built-in **OpportunityPartner** is a legacy object that can't be customized, but you can also use your own custom junction object if you've built one.
  </Accordion>

  <Accordion title="How Introw configures it" icon="sliders">
    Choose **Relation table**, point Introw at the junction object, and confirm the two keys that connect the opportunity to the partner account. Optionally add a **filter** that scopes which rows count. The defaults match the standard Opportunity Partner relation, so most orgs change nothing.
  </Accordion>

  <Accordion title="Roles power multi-partner attribution" icon="users">
    Because each row carries a Role, you can create **one named Introw attribution per role** - filter the relation to `Role = Reseller` for a "Reseller partner" attribution, `Role = Referrer` for a "Referring partner" attribution - all reading the same junction. See multi-tier attribution below.
  </Accordion>

  <Accordion title="On write-back" icon="pen">
    When a partner registers an opportunity through an Introw form, Introw writes a junction row attributing the submitting partner (for the standard object, `Role = "Partner"`, `IsPrimary = true`) - so the record is compliant with your relation model the moment it's created.
  </Accordion>
</AccordionGroup>

| Pros                                                 | Cons                                            |
| ---------------------------------------------------- | ----------------------------------------------- |
| True many-to-many: multiple partners per opportunity | More technical to set up and report on          |
| Carries **roles** and a primary flag                 | Standard OpportunityPartner can't be customized |
| Ideal for resellers, distributors, revenue splits    | A junction is another object to understand      |
| Standard **OpportunityPartner** works out of the box | -                                               |

***

## Method 4 - Custom object

**Best for:** large programs that treat partners as a core part of the data model, with tier, region, focus, and program data on a dedicated record.

A dedicated **Partner** custom object relates to Opportunities, Accounts, and Contacts, and Introw treats it as the partner.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
erDiagram
  PARTNER__C ||--o{ OPPORTUNITY : "Partner__c lookup"
  PARTNER__C ||--o{ CONTACT : "partner people"
  PARTNER__C ||--o| ACCOUNT : "resolves to"
  PARTNER__C {
    string Name
    picklist Tier__c
    string Region__c
  }
  OPPORTUNITY {
    string Name
    number Amount
  }
```

<AccordionGroup>
  <Accordion title="How it works in Salesforce" icon="gear">
    A custom object is your own object with its own fields and relationships. You model partners on it, relate it to opportunities via a lookup (or a junction for many-to-many), and hold tier, region, focus, and program data on the record itself.
  </Accordion>

  <Accordion title="How Introw configures it" icon="sliders">
    Set the **partner object** to your custom object during connect (the "How do you store partners in your CRM?" step). Then attribute opportunities via the lookup or relation that connects them to it. Introw resolves the custom object to the partner and reads its fields into segments, portals, and reporting.
  </Accordion>

  <Accordion title="Trade-off" icon="triangle-exclamation">
    Fully flexible and scalable, but it needs upfront schema design. Best when a single Account or lookup can't capture how you run partners.
  </Accordion>
</AccordionGroup>

| Pros                                                    | Cons                          |
| ------------------------------------------------------- | ----------------------------- |
| Partners are a first-class object with their own schema | Upfront schema design         |
| Rich per-partner data (tier, region, focus, program)    | More moving parts to maintain |
| Relates to opportunities, accounts, and contacts        | Overkill for small programs   |
| Scales to the largest ecosystems                        | -                             |

***

## Multi-tier attribution - more than one partner on an opportunity

Real ecosystems rarely have exactly one partner per opportunity. A referrer surfaces it, a reseller closes it, an implementation partner delivers it. Introw models this natively: **you can define several named attributions on the same object**, each with its own name. You do not need a relation table for this - **every method here can be repeated, including the single-value ones**: add a lookup or picklist per role and map each as its own attribution, so one opportunity credits several partners across tiers.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart LR
  opp["One Opportunity"]
  opp -->|"junction row, Role = Reseller"| r["Reseller partner"]
  opp -->|"junction row, Role = Referrer"| ref["Referring partner"]
  opp -->|"lookup: Delivery Partner"| d["Delivery partner"]
```

You can mix and match the mechanisms to express roles:

<CardGroup cols={3}>
  <Card title="Relation-table roles" icon="users">
    One attribution per **Role** on the junction - Reseller, Referrer, SI.
  </Card>

  <Card title="Multiple lookups" icon="link">
    Separate lookups like "Sourcing Partner" and "Delivery Partner", each mapped independently.
  </Card>

  <Card title="Multiple picklists" icon="list">
    Distinct picklists per role when you're not using relationships yet.
  </Card>
</CardGroup>

<Note>
  Each named attribution is **independently reportable**, so several partners can be credited on one {object_1} - a sourcing partner and an influencing partner side by side - and your commission plans run on whichever attribution(s) you scope them to. Name each attribution clearly and it reads that way in reporting, in the portal, and to partners.
</Note>

***

## Two-way by design - read *and* write

Attribution isn't only about reading what exists. Introw also **writes attribution the same way you defined it**, so the model holds no matter who creates the record.

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart LR
  partner["Partner submits<br/>a form in the portal"] --> introw["Introw form automation"]
  introw -->|"creates the record"| record["New record"]
  introw -->|"attaches the partner via<br/>your configured method"| link["Configured attribution"]
  record --- link
  link --> compliant["Record is born<br/>correctly attributed"]
```

<CardGroup cols={2}>
  <Card title="Backwards compatibility" icon="clock-rotate-left">
    Point Introw at your existing model and every historic {object_2} becomes attributable, in the right partner's pipeline. Nothing to backfill.
  </Card>

  <Card title="Data hygiene going forward" icon="broom">
    A partner registering through a form is attached with the **exact method you configured** - compliant from creation, not reconciled later.
  </Card>

  <Card title="No RevOps work either way" icon="circle-check">
    You never restructure {crm_1}. Tell Introw once how objects link to partners; reading old records and writing new ones follow that one definition.
  </Card>
</CardGroup>

***

## Choosing a method

| Your situation                                 | Recommended method                             | Relationship needed |
| ---------------------------------------------- | ---------------------------------------------- | ------------------- |
| Simplest start, one partner per opp            | Picklist field                                 | None                |
| Clean 1:1 with real partner data               | Lookup to Account                              | Lookup              |
| A fixed few partner roles (sourcing, delivery) | One lookup or picklist per role                | Lookup / none       |
| Many or open-ended partners, or revenue splits | Relation table (OpportunityPartner)            | Junction            |
| Track the role each partner plays              | A field per role, or a filtered relation table | Lookup / junction   |
| Large program, rich partner data               | Custom object                                  | Lookup or junction  |

<Tip>
  Whichever you choose, configuration is the same shape: open **Object Linking**, pick the method, name the attribution, decide if it's commission-eligible, save. Introw handles the rest - no code, no consultant, no RevOps project.
</Tip>

## Set it up

Whichever method you chose, you configure it in the same place: the **Object Linking** screen. This is the same attribution step the connect wizard runs, reopened any time to add or refine a mapping.

<Steps>
  <Step title="Open Object Linking">
    Go to [Integrations](https://app.introw.io/settings/integrations?category=crm), open the connected Salesforce connection with **Configure**, and go to **Which objects do you link with partners?**. Select **Add object**, or open the existing **Opportunity** mapping to edit it. Configure **Opportunity** at minimum, since it is what reporting and commissions run on.
  </Step>

  <Step title="Choose how opportunities attribute to partners">
    On **How do you attribute partners to Opportunity objects?**, pick the method that matches your org: **Custom properties** (a picklist or lookup field on the opportunity) or **Relation table** (a junction object such as an Opportunity Partner relation). This mirrors the methods above.
  </Step>

  <Step title="Configure the method and map values">
    For **Custom properties**, select the field that identifies the partner. For a **Relation table**, point Introw at the relation object and confirm the keys that connect the opportunity to the partner account, and optionally a filter that scopes which rows count. The defaults match a standard Opportunity Partner relation, so adjust only if your org differs. If a field holds coded values rather than partner names, use **Match property values to Introw partners**.
  </Step>

  <Step title="Name the attribution and save">
    Set **What name do you want to use for this attribution?** so the link reads clearly to your team and partners, then select **Add Opportunity attribution** (or **Save** when editing). Confirm when Introw asks you to verify. To credit **more than one partner on the same opportunity**, add another Opportunity attribution with a different lookup, picklist, or relation-table role (for example a "Delivery partner" alongside a "Sourcing partner") - each is its own named attribution. Repeat **Add object** to credit other record types too.
  </Step>
</Steps>

## Verify it worked

Open a partner-influenced {object_3} in {crm_2}. In Introw it shows attributed to the right partner under your attribution name, and that partner's sourced/influenced pipeline reflects it in reporting and commissions. For a partner-created {object_3}, confirm the attribution (association, field, or relation row) was written on the {crm_2} record itself.

## Related

<CardGroup cols={2}>
  <Card title="Connect Salesforce" icon="book-open" href="./connect-salesforce">
    Set up the connection and run this attribution step inside the wizard.
  </Card>

  <Card title="Partner attribution in HubSpot" icon="book-open" href="./attribution-in-hubspot">
    The same depth for HubSpot - properties, association labels, and roles.
  </Card>

  <Card title="Partner attribution in Pipedrive" icon="book-open" href="./attribution-in-pipedrive">
    The property-based method for Pipedrive.
  </Card>

  <Card title="Show & rename CRM fields" icon="table-columns" href="./show-and-rename-crm-fields">
    Put any Salesforce field on your Introw tables, overviews, and partner views - renamed to partner-friendly labels.
  </Card>
</CardGroup>
