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

# Sandbox-First Implementation Guide

> End-to-end sequence for implementing the WeGive Salesforce Nonprofit Cloud integration: build and validate in a Salesforce Sandbox with the WeGive Test dashboard, then repeat in Production with the Live dashboard

This guide is the sequence. It walks a Salesforce Nonprofit Cloud (NPC) implementation from first decisions through Production go-live, and each phase ends with a checkpoint to pass before moving on. The pages linked from each phase remain the reference for individual settings.

It is written for whoever is doing the work: a Salesforce administrator, a consultant, or a WeGive implementation specialist. If your org runs NPSP rather than Nonprofit Cloud, use the [NPSP Implementation Guide](/salesforce-npsp/install-setup/implementation-guide) instead.

## How the two environments pair

| WeGive dashboard | Salesforce org | Purpose |
| - | - | - |
| Test | Sandbox | Build, configure, and validate. Test-mode transactions, no real money. |
| Live | Production | Go-live. Real donors, real money. |

Each connection is authorized separately against its org's My Domain URL, and settings do not carry between the two dashboards.

## What is different from an NPSP implementation

If you have implemented WeGive against NPSP, the NPC path is shorter on the Salesforce side and longer on decisions.

* **No managed package** to install. WeGive works against the standard NPC objects through the REST API (Bulk API 2.0 is used only for `CampaignMember` batch push operations — see [Integration Nuances](/external/onboarding/npc/integration-nuances)). A Remote Site Setting is still required (see Phase 2), same as NPSP.
* There are **no trigger handler exclusions**. NPC has no equivalent of NPSP's trigger framework acting on WeGive's records.
* **Person Accounts must be enabled** before you connect. Individual supporters are Person Accounts, and WeGive discovers the record type at connect time.
* The integration user needs **Fundraising licensing** (a permission set license and a permission set) rather than a System Administrator profile.
* **Pull filters** decide which gift types, payment methods, and statuses are imported. They are seeded from your org's picklists and are the first place to look when records are missing.
* The **Salesforce Nonprofit Cloud** integration must be enabled on the WeGive account before it appears under Integrations.

## Phase 0: Decide before you configure

### Access

* Admin access to the WeGive **Test** and **Live** dashboards, with **Salesforce Nonprofit Cloud** visible under **Settings > Integrations** in both. If it is missing, ask your WeGive contact to enable it before scheduling any Salesforce work.
* System Administrator access to the Salesforce **Sandbox** and **Production**
* A Sandbox refreshed recently enough that its record types, picklists, and designations match Production

### Sandbox data

| Sandbox type | Production data included | Fit |
| - | - | - |
| Developer or Developer Pro | None (metadata only) | Works, but you must create sample Person Accounts, an Organization Account, a Household, a Campaign, a `GiftDesignation`, and a few `GiftTransaction` and `GiftCommitment` records by hand before Phase 5. |
| Partial Copy | A sample of records per object, chosen by a Sandbox template | Recommended. Confirm the template includes Account, Contact, Campaign, CampaignMember, `GiftDesignation`, `GiftTransaction`, `GiftTransactionDesignation`, `GiftCommitment`, `GiftCommitmentSchedule`, `GiftDefaultDesignation`, `GiftSoftCredit`, and `GiftRefund`. A Sandbox with Person Accounts but no gift records proves nothing on pull. |
| Full Copy | Everything | Works. The initial pull takes as long as it will in Production (paginated REST, not Bulk API 2.0 — see Phase 5). |

### Salesforce facts

* Nonprofit Cloud is enabled and configured on the org
* Person Accounts are enabled, and the API names of the Person Account, Organization, and (if used) Household record types
* Whether the org uses Household Accounts at all. If not, household sync stays off.
* The Salesforce API version the org supports. WeGive defaults to 59.0; gateway reference and fee fields on `GiftTransaction` and `GiftRefund` need 60.0 or later.
* The org's `GiftTransaction.Status` and `GiftCommitment.Status` picklist values, and whether any have been customized away from the defaults (Paid, Pending, Failed — these three are dashboard-configurable; `Written-Off` and `Fully Refunded` are hardcoded and NOT configurable, so the org's picklist must contain those exact values — and Active, Closed, Lapsed, Failing, Paused, Draft for commitments)
* The org's `GiftTransaction.PaymentMethod` picklist values
* The `GiftType` values in use (Individual and Organizational by default)
* Any other automation that writes to Account, `GiftTransaction`, `GiftCommitment`, or `GiftDesignation` (Flows, Apex, other vendors)

### Integration decisions

* Which Salesforce user WeGive will run as (see Phase 1). A dedicated user is strongly recommended.
* Whether to sync Person Accounts that have no email address (the email filter is off by default on NPC)
* Whether the org uses designation splits, which decides the **Fund allocations** setting
* Whether to pull all `GiftCommitment` records or only Active ones
* Which `AccountContactRelation` roles should grant a supporter a login on the related company, if any
* Which Account record types to hide from sync (vendors, partners, other non-supporter record types)
* Sync direction per object: Pull, Push, or both. Defaults suit most orgs.
* Which custom fields must map between the systems. WeGive does not create fields on NPC objects; the Salesforce admin creates them first. The [Data Mapping Overview](/external/onboarding/npc/data-mapping/overview) lists the defaults.
* Which triggered messages (receipts, welcome emails, recurring gift notices) exist in WeGive, so they can be paused during the initial data pull

<Tip>
  Record these in one place. You will enter the same values in the Live dashboard during Phase 6.
</Tip>

**Checkpoint 0:** every item above is known or marked not applicable, and Salesforce Nonprofit Cloud appears under Integrations in both dashboards.

## Phase 1: Prepare the Sandbox and the integration user

Work in the Sandbox for Phases 1 through 5.

### 1a. Verify the org

Confirm each item in [Setup Requirements](/external/onboarding/npc/setup-requirements): Nonprofit Cloud enabled, Person Accounts enabled, the Person Account and Organization record types present, and the Household record type present if the org uses households. If any of these differ from Production, refresh the Sandbox or fix Production first.

### 1b. Create the integration user

WeGive authorizes as a single Salesforce user, and every record WeGive creates or edits is stamped with that user. Use a dedicated user, never a person's login.

<Steps>
  <Step title="Create the user">
    **Setup > Users > New User**. Suggested values:

    | Field | Value |
    | - | - |
    | First Name | `WeGive` |
    | Last Name | `Integration` |
    | Email | A monitored mailbox at the organization. WeGive does not use this address. |
    | Username | `wegive@yourorg.org` (must be globally unique across Salesforce) |
    | User License | Salesforce |
    | Profile | A profile with API Enabled. System Administrator is simplest; a narrower profile works if it grants the object access below. |

    Salesforce appends the Sandbox name to usernames in a Sandbox (for example `wegive@yourorg.org.uat`).
  </Step>

  <Step title="Assign Fundraising licensing">
    On the user record, assign the **Fundraising Access** permission set license, then the **Fundraising User** permission set. Without both, the user cannot read or write the Gift objects and every push fails with an insufficient access error.
  </Step>

  <Step title="Confirm object access">
    The user needs read and write access to Account, Contact, Campaign, CampaignMember, `GiftTransaction`, `GiftTransactionDesignation`, `GiftCommitment`, `GiftCommitmentSchedule`, `GiftDefaultDesignation`, `GiftDesignation`, `GiftSoftCredit`, `GiftRefund`, and `GiftTribute`, plus API Enabled and Bulk API access. See [Integration user](/external/onboarding/npc/setup-requirements#integration-user).
  </Step>

  <Step title="Set the password and verify login">
    Log in once as the integration user in a private browser window to clear the initial password reset and confirm the user can reach the org. You will use this login in Phase 3 to authorize WeGive.
  </Step>
</Steps>

<Note>
  Do not set an IP login range on the integration user's profile. WeGive does not connect from a fixed IP range.
</Note>

**Checkpoint 1:** you can log in to the Sandbox as the integration user, the user holds the Fundraising Access license and Fundraising User permission set, and Person Accounts are enabled.

## Phase 2: Create the External Client App

Follow [External Client App and Connection Setup](/external/onboarding/npc/install-setup/external-client-app) Step 2 exactly: create the app, set the OAuth scopes and flow settings, relax IP restrictions, and copy the Consumer Key and Secret.

Three details trip people up:

* **Activation delay.** A new External Client App can take up to 10 minutes to become usable. Create it before doing anything else in this phase.
* **Callback URL.** The NPC integration uses its own callback, `https://api.wegive.com/api/oauth/npc/callback`. It is not the same as the NPSP callback.
* **Consumer Secret is shown once.** Store both values in a password manager immediately.

**Checkpoint 2:** the app exists with the NPC callback URL and the `api`, `refresh_token`, and `offline_access` scopes, IP restrictions are relaxed, and the Consumer Key and Secret are stored.

## Phase 3: Connect the WeGive Test dashboard

Follow [Step 3 on the connection page](/external/onboarding/npc/install-setup/external-client-app#step-3-connect-wegive-to-salesforce). In short: sign out of every Salesforce session, open **Settings > Integrations > Salesforce Nonprofit Cloud > Connection** in the Test dashboard, enter the Sandbox's **My Domain URL** as the Salesforce Login URL, paste the Consumer Key and Secret, save, click **Test Connection**, and sign in as the integration user when Salesforce prompts.

When the header shows **OAuth connected**, WeGive has read your org and stored the record type IDs, supported API versions, picklist values, and `AccountContactRelation` roles. Leave **Enable Integration** off until Phase 4 is complete.

| Symptom | Likely cause | Fix |
| - | - | - |
| Authorization error immediately after creating the app | App not yet active | Wait 10 minutes and retry |
| Redirect URI mismatch | Callback URL typo, or the NPSP callback was used | Set it to `https://api.wegive.com/api/oauth/npc/callback` exactly |
| Login page is for the wrong org | Salesforce Login URL points at Production, or a personal session was active | Sign out, correct the My Domain URL, authorize again as the integration user |
| Record type IDs are blank after connecting | Person Accounts were not enabled, or the user cannot see the record types | Enable Person Accounts or fix the user's access, then disconnect and authorize again so WeGive re-discovers them |

**Checkpoint 3:** the header shows **OAuth connected** and the Person Account and Organization record type IDs are populated under Record types.

## Phase 4: Configure the integration in the Test dashboard

Use the values from Phase 0. Every setting is defined in [Configuration Options](/external/onboarding/npc/configuration-options).

<Steps>
  <Step title="Connection settings">
    Confirm the discovered **API version**. Move above 59.0 only if the org supports it and you want gateway reference and fee fields synced. Leave **Pull frequency** at its default.
  </Step>

  <Step title="Record types">
    Confirm the Person Account and Organization record type IDs. Enter the Household record type ID only if the org uses households; leaving it blank turns household sync off. Add any non-supporter Account record types (vendors, partners) to **Hidden record types**.
  </Step>

  <Step title="Sync toggles">
    Turn on Pull and Push for the objects decided in Phase 0 and leave the rest off. Leave every **Pull deleted** toggle off unless the organization has decided a deletion in Salesforce should delete the WeGive record.
  </Step>

  <Step title="Sync behavior">
    Set **Fund allocations** on if the org uses designation splits, off if every gift has a single designation. Set **Sync all recurring donations** according to the Phase 0 decision. Turn on **Send processing ACH as success** only if the org wants ACH gifts to close before settlement. Under **Login contact roles**, keep only the roles that should grant supporter logins.
  </Step>

  <Step title="Pull filters">
    Review the seeded **Gift types**, **Payment methods**, **Transaction statuses**, and **Commitment statuses**. Remove values the org does not want imported (for example, Unpaid or Draft). A record whose value is missing from these lists is skipped silently on pull.
  </Step>

  <Step title="Status mapping and payment method labels">
    If the org has customized the `GiftTransaction.Status` picklist, override the Success, Pending, and Failed values to match exactly (these three are the only dashboard-configurable status settings). `Written-Off` (cancelled) and `Fully Refunded` are hardcoded — not overridable — so confirm the org's picklist contains those exact literal values instead; if it doesn't, pushes for cancelled/refunded transactions will fail. If the `PaymentMethod` picklist does not contain `Credit Card` and `ACH`, change the card and bank labels to values that exist; a value not in the picklist fails the push.
  </Step>

  <Step title="Custom fields in Salesforce, then in WeGive">
    Have the Salesforce admin create any custom fields on the NPC objects first, and confirm the integration user has field-level access. Then create the matching custom fields in WeGive under **Settings > Data & Customization > Custom Fields**.
  </Step>

  <Step title="Mapping Rules">
    Review the default rules for Person Accounts, Organization Accounts, Households, Gift Transactions, and Gift Commitments against the [data mapping pages](/external/onboarding/npc/data-mapping/overview). Add custom field rules and save.
  </Step>

  <Step title="Pause triggered messages">
    Under **Settings > Communications > Triggers**, turn off every triggered message before enabling the integration. The initial pull imports historical supporters and gifts, and a live trigger can send a receipt or welcome email for every one of them.
  </Step>
</Steps>

<Warning>
  Configuration is per dashboard. Nothing set in the Test dashboard carries to Live. Document every section when you finish this phase so Phase 6 is a copy exercise.
</Warning>

**Checkpoint 4:** every section matches the Phase 0 decisions and is saved, mapping rules are reviewed, and triggers are paused.

## Phase 5: Validate in the Sandbox

On the **Connection** tab, turn on **Enable Integration**, then click **Sync** to start the first pull. WeGive pushes changes to Salesforce within about five minutes and pulls on the configured schedule (15 minutes by default). Large Sandboxes import through paginated REST queries, not Bulk API 2.0 — Bulk API 2.0 in this integration is scoped only to `CampaignMember` batch push operations (see [Integration Nuances](/external/onboarding/npc/integration-nuances)) — and the initial pull can take an hour or more regardless. Watch progress and errors under **Settings > Integrations > Integration Logs**.

### 5a. Full data pull

Let the pull finish, then reconcile counts:

| Salesforce report | WeGive view | Expected relationship |
| - | - | - |
| Person Accounts, excluding hidden record types (and excluding those with no email if the filter is on) | Supporters | Equal, allowing for records WeGive merged by email |
| Organization Accounts, excluding hidden record types | Companies | Equal |
| Household Accounts (if enabled) | Households | Equal |
| `GiftTransaction` records with Status Paid and a `GiftType` and `PaymentMethod` in the pull filters | Transactions with Success status | Equal in count and total `OriginalAmount` |
| `GiftCommitment` records with Status Active (all statuses if Sync all recurring donations is on) and `RecurrenceType` OpenEnded | Active recurring plans | Equal |
| `GiftDesignation` records | Funds | Equal |
| Active Campaigns | Campaigns | Equal |

Then open five supporters and confirm name, email, address, household, and giving history match Salesforce record for record. Keep the counts; they are the baseline for the Production pull.

If a category of records is missing entirely, check the pull filters before anything else. If nothing appears after thirty minutes, check Integration Logs.

### 5b. Push a new supporter and one-time gift

1. In the Test dashboard, make a one-time gift in test mode through a giving form or the virtual terminal, using a new name and email that does not exist in the Sandbox.
2. Wait five to ten minutes.
3. In the Sandbox, find the Person Account by email. Verify:
   * A Person Account exists with the configured Person Account record type
   * A `GiftTransaction` exists with `DonorId` pointing at that Account, the correct `OriginalAmount` and `TransactionDate`, Status equal to the configured Success value, and `PaymentMethod` equal to the configured card label
   * Exactly one `GiftTransactionDesignation` row for the gift's fund (or, with Fund allocations on, one row per allocation summing to 100 percent)
   * Created By on every record is the integration user
4. Open the supporter in WeGive and confirm the Salesforce ID is populated on the supporter and the transaction.

### 5c. Push a gift to an existing supporter

Make a second test gift using the email of a Person Account that already existed in the Sandbox. Verify WeGive matched the existing Account instead of creating a duplicate.

### 5d. Refund

Refund the gift from 5b in the Test dashboard. After the push delay, confirm a `GiftRefund` record exists linked to the `GiftTransaction`, with the refund amount and date, and that the transaction's status changed to `Fully Refunded` (this value is hardcoded, not one of the dashboard's configurable status settings).

### 5e. Recurring gift

Start a monthly test recurring gift. Confirm a `GiftCommitment` with `RecurrenceType` OpenEnded exists for the supporter, with one `GiftCommitmentSchedule` row carrying the amount, `TransactionPeriod` Month, `TransactionInterval` 1, and the start date. Confirm the first charge produced a `GiftTransaction` with `GiftCommitmentId` set.

### 5f. Pull an edit from Salesforce

Edit the mobile phone on a synced Person Account in the Sandbox. Within one pull interval the change should appear on the supporter in WeGive. Then edit the same supporter's phone in WeGive and confirm it appears on the Person Account. This proves both directions.

### 5g. Designation created in Salesforce

Create a new `GiftDesignation` in the Sandbox. After a pull, confirm it appears as a fund in WeGive. This proves designations flow in so the org can keep managing them in Salesforce.

### 5h. Company gift (if the org tracks organizational giving)

Make a test gift as a company. Confirm an Organization Account with the configured record type exists and the `GiftTransaction` points at it, with `GiftType` Organizational.

### 5i. Integration log review

Open **Settings > Integrations > Integration Logs** and confirm there are no repeating errors. Check **Integration Locks** is empty or contains only records you deliberately broke.

**Checkpoint 5:** every applicable test passes and Integration Logs show no repeating errors.

## Phase 6: Repeat in Production with the Live dashboard

Production setup is the same sequence with three differences: the org, the dashboard, and the My Domain URL.

| Step | Sandbox pass | Production pass |
| - | - | - |
| Integration user | Created in Sandbox | Create in Production (or confirm it exists after a refresh). Username has no suffix. Assign the Fundraising license and permission set again. |
| External Client App | Created in Sandbox | Create again in Production. A new Consumer Key and Secret are generated. |
| Salesforce Login URL | Sandbox My Domain | Production My Domain |
| Record type IDs | Discovered from Sandbox | Discovered again from Production; they are different IDs even for same-named record types |
| Pull filters | Seeded from Sandbox picklists | Seeded again from Production; re-apply any removals |
| WeGive dashboard | Test | Live, using the Phase 4 documentation |
| Triggered messages | Pause before sync | Pause before sync, re-enable after the pull reconciles |
| Validation | Test-mode gifts, count reconciliation | Count reconciliation against the 5a baseline, then a small live gift (a real card, a small amount, refunded afterward) |

<Warning>
  Do not turn on **Enable Integration** in the Live dashboard until every Phase 4 setting has been re-entered and reviewed, including the pull filters and status mapping. The first sync pulls the org's history into WeGive and begins pushing WeGive activity into Production.
</Warning>

### Go-live sequence

Connecting and pulling are separate events and can be days or weeks apart. Connect early so authorization and discovery problems surface with time to spare. Pull only when the organization is ready to run on WeGive data.

1. Complete Phases 1 through 4 in Production and the Live dashboard. Leave **Enable Integration** off.
2. Confirm every trigger in the Live dashboard is paused.
3. Choose a quiet window for the full pull. Turn on **Enable Integration** and click **Sync** at the start of the window. Large orgs import through paginated REST queries (not Bulk API 2.0 — see Phase 5) and can take hours; do not change configuration while it runs.
4. Reconcile counts using the 5a table.
5. Make a small live gift and refund it. Confirm the `GiftTransaction`, its designation, and the `GiftRefund` in Production.
6. Re-enable triggered messages only after the pull is complete and reconciled.
7. Review Integration Logs after the first full day and again after the first week.

**Checkpoint 6:** the Production pull reconciles to Salesforce, the live gift landed correctly, triggered messages are back on deliberately, and the first day's Integration Logs are clean.

## After go-live

* A Sandbox refresh removes the External Client App and the integration user's licensing on the Sandbox side. Recreate them and re-authorize the Test dashboard after every refresh; record type IDs are re-discovered on authorization.
* If the org enables Person Accounts, adds record types, or changes the `Status` or `PaymentMethod` picklists after connecting, disconnect and authorize again so WeGive re-discovers them, then review the pull filters.
* Moving to a newer API version affects every call the integration makes. Test it in the Sandbox first.
* The integration user and app credentials belong to the organization, not WeGive. Store them accordingly.

## Quick reference: what lives where

| Item | Salesforce Sandbox | Salesforce Production | WeGive Test | WeGive Live |
| - | - | - | - | - |
| Integration user, Fundraising license and permission set | Create, assign | Create, assign | | |
| External Client App | Create | Create | | |
| Custom fields on NPC objects | Create | Create | | |
| Salesforce Login URL, Consumer Key and Secret | | | Enter Sandbox values | Enter Production values |
| Record types, sync toggles, filters, status mapping, mapping rules | | | Configure | Configure again |
| Triggers (Communications) | | | Pause before sync | Pause before sync, re-enable after pull |
| Enable Integration toggle | | | On after Phase 4 | On after Phase 6 review |


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