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

# Campaign Member

> Mapping between WeGive Campaign Donors and Salesforce Campaign Members

**Salesforce Object:** `CampaignMember` (standard Salesforce object)<br />**WeGive Model:** CampaignDonor

## Overview

This document describes how campaign member data syncs between WeGive and Salesforce. Campaign Members represent the relationship between a donor and a campaign, tracking which supporters are associated with specific fundraising initiatives.

In WeGive, these are called "Campaign Donors" and serve the same purpose.

Campaign Members link to a Contact by default. If your Salesforce org has enabled **Accounts as Campaign Members**, the integration also supports linking company donors through the `AccountId` field. See [Contact and Account Members](#contact-and-account-members).

***

## How Campaign Member Data Syncs

### Direction

* **Import from Salesforce** - Data imports from Salesforce into WeGive only
* **Export to Salesforce** - Data exports from WeGive to Salesforce only
* **Both Ways** - Data syncs in both directions

### Mapping Types

* **Hard-coded** - Built into the integration logic and cannot be changed. There are no configurable mapping rules for campaign members.

***

## Sync Configuration

* **Pull campaign donors** - Enables the scheduled import of Campaign Members
* **Push campaign donors** - Enables the export of WeGive campaign donors
* **`pull_deleted_campaign_donors`** - When enabled, Campaign Members deleted in Salesforce are also removed in WeGive

***

## Sync Triggers

### From WeGive to Salesforce (Export)

* **Campaign Donor Created:** A new donor is added to a campaign in WeGive. A Campaign Member is created in Salesforce.
* **Campaign Donor Updated:** Because `CampaignId` and `ContactId`/`AccountId` are read-only after creation and no other fields are synced, an update in WeGive sends **nothing** to Salesforce.
* **Campaign Donor Deleted:** A donor is removed from a campaign in WeGive. The Campaign Member is deleted in Salesforce.

### From Salesforce to WeGive (Import)

* **Last Modified Date:** WeGive periodically polls Salesforce for Campaign Members whose `LastModifiedDate` falls in the window since the last sync
* **Deleted Members:** When `pull_deleted_campaign_donors` is enabled, the integration also queries for members with `IsDeleted = true` in the same window and removes the matching WeGive campaign donors

***

## Sync Process Overview

### Pulling Data from Salesforce

The integration selects `Id`, `CampaignId`, `ContactId`, `Status`, and `LastModifiedDate` (plus `AccountId` when Accounts as Campaign Members is enabled). For each record it:

1. Loads the WeGive campaigns matching the `CampaignId` values
2. Loads the WeGive individual donors matching the `ContactId` values, and, when applicable, company donors matching the `AccountId` values
3. Creates or updates the campaign donor relationship

<Note>
  `Status` is queried but is **not** stored in WeGive. Campaign member status lives only in Salesforce.
</Note>

### Pushing Data to Salesforce

Before creating a Campaign Member, the integration ensures:

1. **Donor exists in Salesforce:** An individual donor must have a `salesforce_id` (Contact); a company donor must have a `salesforce_account_id` (Account). If missing, the donor is pushed first.
2. **Campaign exists in Salesforce:** The campaign must have a `salesforce_id`. If missing, the campaign is pushed first.

**Duplicate Prevention:** Before creating a new Campaign Member, the integration queries Salesforce for an existing member with the same `CampaignId` and `ContactId` (or `AccountId`). If found, the WeGive campaign donor is linked to that record instead of creating a duplicate. If Salesforce still rejects the insert as a duplicate, the integration re-queries by `CampaignId` and `ContactId` and links to the match.

### Standard Field Mappings

| Salesforce Field | WeGive Field | WeGive API Field | Direction | Type | Notes |
| :- | :- | :- | :- | :- | :- |
| Id | Salesforce ID | salesforce\_id | Import from Salesforce | Hard-coded | Salesforce's unique identifier for this campaign member |
| CampaignId | Campaign Salesforce ID | campaign.salesforce\_id | Both Ways | Hard-coded | Links to the Campaign; read-only after creation |
| ContactId | Donor Salesforce ID | donor.salesforce\_id | Both Ways | Hard-coded | Used for individual donors |
| AccountId | Donor Salesforce Account ID | donor.salesforce\_account\_id | Both Ways | Hard-coded | Used for company donors only when Accounts as Campaign Members is enabled |
| Status | (not stored) | | Import from Salesforce | Hard-coded | Queried on import but not saved; never set on export |

***

## Important Notes

### Contact and Account Members

* **Individual donors** are always linked through `ContactId`.
* **Company donors** are linked through `AccountId` only if the Salesforce org has enabled Accounts as Campaign Members. The integration detects this automatically by checking whether the `CampaignMember` object exposes an `AccountId` field (the result is cached for up to a day).
* When the feature is not enabled, campaign donors for company donors are **skipped** on push with a warning, and `AccountId` is not read on pull.

### Status Field

The `Status` field is owned by Salesforce. The integration does not export it and does not store the imported value. Manage status in Salesforce.

### Deletion Handling

**WeGive to Salesforce:** When a campaign donor that already has a `salesforce_id` is deleted in WeGive, the integration issues a delete for the Campaign Member record. The donor and campaign records remain.

**Salesforce to WeGive:** When `pull_deleted_campaign_donors` is enabled, Campaign Members with `IsDeleted = true` are matched by `salesforce_id` and the WeGive campaign donor is deleted. The donor and campaign remain. If the setting is off, Salesforce deletions are not reflected in WeGive.

### Multi-Entity Orgs

In a multi-entity Salesforce instance, the import is scoped through the parent Campaign's `wegive__WeGive_Entity__c` field when the campaign domain is entity-scoped.

***

## Campaign Member Matching & Create/Update Logic

### When WeGive Exports a Campaign Donor to Salesforce

1. **Ensure prerequisites** (donor and campaign pushed if they lack Salesforce IDs).
2. **If the campaign donor already has a `salesforce_id`:**
   * Deleted in WeGive: **DELETE** the Campaign Member
   * Not deleted: **no action** (nothing mutable to update)
3. **If there is no `salesforce_id`:**
   * Query Salesforce for a member with the same `CampaignId` and `ContactId`/`AccountId`
   * If found: store its ID on the WeGive campaign donor ("link")
   * If not found: **CREATE** a new Campaign Member

### When Salesforce Exports a Campaign Member to WeGive

1. Find the WeGive campaign donor by `salesforce_id`
2. If not found, resolve the donor (by `ContactId`, then `AccountId`) and campaign (by `CampaignId`) and look for an existing relationship between them
3. If still not found, create a new campaign donor. If the donor or the campaign cannot be found in WeGive, the record is skipped with an error and will be retried when it is next modified in Salesforce.
4. Store the Salesforce Campaign Member ID and save

***

## Required Fields

**For WeGive to Salesforce:**

* CampaignId
* ContactId or AccountId

**For Salesforce to WeGive:**

* Id
* CampaignId
* ContactId or AccountId (the matching donor must already exist in WeGive)

***

## Troubleshooting

**Campaign member not syncing:**

* Verify the donor has a `salesforce_id` (individual) or `salesforce_account_id` (company)
* Check that the campaign has a `salesforce_id`
* Confirm the Pull / Push campaign donors toggles are enabled

**Company donors not syncing:**

* Enable Accounts as Campaign Members in Salesforce; without it, company campaign donors are skipped

**Deleted members reappearing or lingering:**

* Confirm `pull_deleted_campaign_donors` is enabled for Salesforce-side deletions
* Ensure no other process is recreating the relationship

**Status field not updating:**

* The integration neither imports nor exports status; manage it in Salesforce

**Changes in WeGive not reaching Salesforce:**

* Only creation and deletion are synced; there are no updatable fields on a Campaign Member

***

## Related Documentation

* [Campaign](./campaign)
* [Contact](./contact)

*Verified against the integration source, September 2026.*


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