> ## Documentation Index
> Fetch the complete documentation index at: https://wegive.com/docs/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)\
**WeGive Model:** CampaignDonor

## Overview

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

In WeGive, these are called "Campaign Donors" and serve the same purpose - linking donors to campaigns for targeted communication, reporting, and engagement tracking.

**Important Note:** Campaign Members in Salesforce can only link to Contacts, not Accounts. This means only individual donors (not companies) can be added as campaign members through this integration.

***

## 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

***

## Sync Triggers

### From WeGive to Salesforce (Export)

Campaign Member data is exported from WeGive to Salesforce when:

* **Campaign Donor Created:** A new donor is added to a campaign in WeGive
* **Campaign Donor Updated:** An existing campaign donor relationship is modified in WeGive
* **Campaign Donor Deleted:** A donor is removed from a campaign in WeGive

The export happens automatically after the create, update, or delete action in WeGive.

### From Salesforce to WeGive (Import)

Campaign Member data is imported from Salesforce to WeGive based on:

* **Last Modified Date:** WeGive periodically polls Salesforce for Campaign Members that have been modified since the last sync
* **Sync Frequency:** The integration checks for updated Campaign Members on a scheduled basis (frequency varies by integration configuration)
* **Modified Field Tracking:** Only Campaign Members with a `LastModifiedDate` newer than the last successful sync are pulled into WeGive
* **Deleted Members:** The integration tracks deleted campaign members via `IsDeleted = true` queries

This means:

* Creating a new Campaign Member in Salesforce will import it to WeGive on the next sync cycle
* Updating an existing Campaign Member in Salesforce will trigger an import to WeGive on the next sync cycle
* Deleting a Campaign Member in Salesforce will remove it from WeGive on the next sync cycle
* The sync is based on Salesforce's `LastModifiedDate` field, not individual field changes

***

## Sync Process Overview

### Campaign Member-Level Synchronization

WeGive syncs campaign members at the individual relationship level, maintaining the connection between donors and campaigns. This includes membership status and basic relationship tracking.

### Pulling Data from Salesforce

When pulling data from Salesforce, WeGive queries Campaign Member records based on the last modified date. The integration pulls data from the Campaign Member record and its related objects.

The import process includes:

1. **Query Campaign Members:** Fetches Campaign Member records by last modified date
2. **Load Related Campaigns:** Loads campaigns that match the Campaign IDs from the members
3. **Load Related Donors:** Loads donors (contacts) that match the Contact IDs from the members
4. **Create or Update:** Creates new or updates existing campaign donor relationships in WeGive

**Deleted Members:** The integration specifically queries for deleted campaign members:

sql

```
SELECT Id, LastModifiedDate, IsDeleted FROM CampaignMember 
WHERE IsDeleted = true
```

These are then removed from WeGive to maintain sync.

### Pushing Data to Salesforce

When a Campaign Donor is created or updated in WeGive, the integration ensures all prerequisites exist before creating the Campaign Member in Salesforce.

**Prerequisites for Creating Campaign Members:** Before creating a campaign member in Salesforce, the integration ensures:

1. **Donor exists in Salesforce:** The donor must have a `salesforce_id` (Contact ID)
2. **Campaign exists in Salesforce:** The campaign must have a `salesforce_id`

The integration will automatically push the donor and campaign if they don't have Salesforce IDs yet.

**Duplicate Prevention:** Before creating a new Campaign Member, the integration checks if one already exists:

* Queries for existing Campaign Member with matching `CampaignId` and `ContactId`
* If found, links the WeGive campaign donor to that existing Campaign Member
* If not found, creates a new Campaign Member

This prevents duplicate campaign member records in Salesforce.

### 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                                   |
| ContactId        | Donor Salesforce ID    | donor.salesforce\_id    | Both Ways              | Hard-coded | Links to the Contact (individual donor)                 |
| Status           | Status                 | status                  | Import from Salesforce | Hard-coded | Membership status (e.g., "Sent", "Responded")           |
| LastModifiedDate | Last Modified          | (tracking)              | Import from Salesforce | Hard-coded | When the membership was last updated                    |

## Important Notes

### Contact-Only Limitation

Campaign Members in Salesforce can only link to Contacts, not Accounts:

* **Individual donors** (WeGive donor type = 'individual') can be added as campaign members
* **Company donors** (WeGive donor type = 'company') cannot be added as campaign members through this integration
* This is a Salesforce limitation, not a WeGive limitation

If you try to add a company donor to a campaign in WeGive, the sync will skip that relationship or fail.

### Status Field

The `Status` field in Salesforce tracks the member's response to the campaign:

* Common values: "Sent", "Responded", "Declined", etc.
* Status values are defined by picklist on the Campaign object
* On import, WeGive stores the status value
* On export, WeGive does not set the status (Salesforce defaults apply)

### Automatic Donor and Campaign Push

When creating a campaign member, the integration automatically ensures prerequisites:

1. If the donor doesn't have a `salesforce_id`, the donor is pushed first
2. If the campaign doesn't have a `salesforce_id`, the campaign is pushed first
3. Then the campaign member relationship is created

This cascading push ensures data integrity without manual intervention.

### Deletion Handling

When a campaign donor is deleted in WeGive:

* The integration marks it for deletion
* On the next push, it deletes the Campaign Member in Salesforce
* The donor and campaign records remain - only the relationship is deleted

When a Campaign Member is deleted in Salesforce:

* The integration detects it through the deleted records query
* The campaign donor relationship is removed from WeGive
* The donor and campaign records remain - only the relationship is deleted

***

## Campaign Member Matching & Create/Update Logic

### When WeGive Exports a Campaign Donor to Salesforce

The integration uses the following logic:

**Step 1: Ensure Prerequisites Exist**

* Check if the donor has a `salesforce_id`
  * If not, push the donor first
* Check if the campaign has a `salesforce_id`
  * If not, push the campaign first

**Step 2: Check for Existing Campaign Member** The integration queries Salesforce for an existing Campaign Member:

sql

```
SELECT Id, CampaignId, ContactId FROM CampaignMember 
WHERE CampaignId = '[campaign_salesforce_id]' 
AND ContactId = '[donor_salesforce_id]'
```

**Step 3: Determine Action**

* If existing Campaign Member found:
  * Store the Salesforce ID on the WeGive campaign donor
  * Do not create a duplicate
  * This is considered "linking" to the existing record
* If the WeGive campaign donor has a `salesforce_id`:
  * If not deleted: **UPDATE** the existing Campaign Member
  * If deleted: **DELETE** the Campaign Member in Salesforce
* If no `salesforce_id` and no existing member found:
  * **CREATE** a new Campaign Member in Salesforce

**Note:** This dual-check approach prevents duplicates even if the same donor-campaign relationship is created in both systems.

### When Salesforce Exports a Campaign Member to WeGive

**Step 1: Find or Create Campaign Donor** The integration searches for an existing campaign donor:

1. First, try to find by `salesforce_id`
2. If not found, try to find by matching `donor_id` and `campaign_id`
3. If still not found, create a new campaign donor

**Step 2: Verify Related Records**

* Find the donor in WeGive by matching the `ContactId` to `salesforce_id`
  * If donor not found, throw an exception
* Find the campaign in WeGive by matching the `CampaignId` to `salesforce_id`
  * If campaign not found, throw an exception

**Step 3: Update Campaign Donor**

* Link the campaign donor to the donor
* Link the campaign donor to the campaign
* Store the Salesforce Campaign Member ID
* Save the record

### Deleted Campaign Members from Salesforce

The integration handles deleted members through a separate query:

* Queries Campaign Members where `IsDeleted = true`
* Finds matching campaign donors in WeGive by `salesforce_id`
* Deletes the WeGive campaign donor relationship

### Why This Matters

This matching logic ensures:

* No duplicate campaign member relationships are created
* Both systems can independently create the same relationship without conflicts
* Deletions are properly synced in both directions
* Prerequisites (donor and campaign) always exist before creating the relationship

***

## Required Fields

**For WeGive to Salesforce:**

* CampaignId (Campaign Salesforce ID)
* ContactId (Donor Salesforce ID)

**For Salesforce to WeGive:**

* Id (Salesforce Campaign Member ID)
* CampaignId (Campaign Salesforce ID)
* ContactId (Donor Salesforce ID)

## Usage in WeGive

Campaign Donors in WeGive are used for:

* **Targeted Communication:** Send emails or messages to campaign supporters
* **Segmentation:** Create lists of donors interested in specific campaigns
* **Engagement Tracking:** Monitor which campaigns donors engage with
* **Follow-up:** Identify donors to thank or solicit for future giving
* **Reporting:** Analyze donor participation across campaigns
* **Multi-touch Attribution:** Track which campaigns influenced a donor's giving

***

## Usage in Salesforce

Campaign Members in Salesforce are used for:

* **Marketing Automation:** Target supporters with campaign-specific messaging
* **Response Tracking:** Monitor who responded to campaign appeals
* **ROI Analysis:** Calculate campaign effectiveness based on member conversion
* **Engagement Scoring:** Track donor engagement across multiple campaigns
* **Email Marketing:** Sync with marketing automation platforms
* **Reporting:** Standard Salesforce campaign reports show member statistics
* **Campaign Influence:** Track multi-touch attribution in the opportunity lifecycle

***

## Integration Rules

Currently, campaign member field mappings are entirely hard-coded. There are no configurable mapping rules for campaign members, as the data structure is standardized across Salesforce implementations.

The integration focuses on maintaining the core relationship between donors and campaigns without additional custom fields.

***

## Best Practices

1. **Add donors to campaigns early** in their engagement journey
2. **Use consistent campaign selection** when processing donations
3. **Clean up old memberships** for inactive campaigns to reduce clutter
4. **Monitor sync logs** for failed campaign member creations
5. **Ensure donors exist** before adding them to campaigns
6. **Don't manually create duplicates** - let the integration handle deduplication
7. **Use campaign hierarchies** to organize related campaign memberships
8. **Track status changes** in Salesforce to understand donor response
9. **Coordinate with marketing team** on campaign member usage
10. **Document when to add members** vs. when donations automatically create them

***

## Troubleshooting

**Campaign member not syncing:**

* Verify the donor has a `salesforce_id` (is a Contact, not just an Account)
* Check that the campaign has a `salesforce_id`
* Ensure the donor is an individual, not a company
* Verify the integration has access to the CampaignMember object

**Duplicate campaign members:**

* The integration should prevent duplicates automatically
* If duplicates exist, they may have been created outside the integration
* Merge duplicates in Salesforce, keeping the one with the WeGive relationship

**Company donors not syncing:**

* Campaign Members can only link to Contacts in Salesforce
* Company donors cannot be added as campaign members
* This is a Salesforce limitation, not an integration issue

**Deleted members reappearing:**

* Verify the deleted campaign members query is running
* Check that deletions are processing in both directions
* Ensure no competing process is recreating the relationships

**Missing prerequisites error:**

* The donor or campaign doesn't exist in Salesforce
* Run a manual sync of donors and campaigns first
* Check that the prerequisite records have valid Salesforce IDs

**Status field not updating:**

* The integration imports status but does not export it
* Status updates must be made in Salesforce
* Use Salesforce workflows or process builder to automate status changes

***

## Understanding Hard-coded Mappings

All campaign member field mappings are hard-coded because:

* The CampaignMember object structure is standardized in Salesforce
* The relationship is simple: just donor + campaign + status
* Additional complexity is handled through Campaign object fields, not member fields
* Custom fields on Campaign Members are rarely used in practice
