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

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

WeGive detects whether the org you authorize is a Sandbox or Production and refuses a mismatched pairing. A Test dashboard cannot connect to Production and a Live dashboard cannot connect to a Sandbox.

## Phase 0: Decide before you configure

Nearly every stalled implementation traces back to one of these items being unknown on the day of setup.

### Access

* Admin access to the WeGive **Test** and **Live** dashboards
* System Administrator access to the Salesforce **Sandbox** and **Production**
* A Sandbox refreshed recently enough that its NPSP settings, record types, and GAUs match Production

### Sandbox data

The validation phase depends on what data the Sandbox holds.

| Sandbox type | Production data included | Fit |
| - | - | - |
| Developer or Developer Pro | None (metadata only) | Works, but you must create sample Contacts, Households, Opportunities, Recurring Donations, and Campaigns by hand before Phase 6. |
| Partial Copy | A sample of records per object, chosen by a Sandbox template | Recommended. Real record shapes without full data volume. Confirm the template includes Contact, Account, Opportunity, Payment, Allocation, GAU, Recurring Donation, and Campaign. |
| Full Copy | Everything | Works. The initial pull in Phase 6 takes as long as it will in Production, which helps estimate the go-live window but slows iteration. |

### Salesforce facts

* Salesforce edition (Enterprise, Unlimited, or Developer; Professional is not supported)
* NPSP version (**Setup > Installed Packages**; 3.220 or higher is required)
* Household Account model in use (required)
* Enhanced Recurring Donations (RD2) enabled (required)
* Whether the org uses NPSP **Payments** (`npe01__OppPayment__c`) as the record of money received
* Whether the org uses **GAU Allocations**, and if so the default GAU
* Opportunity record type API names for donations, and which represent non-tax-deductible revenue or should be hidden from WeGive entirely
* The exact Opportunity **Stage** names the org uses for Closed Won, Pledged, Refunded, and Closed Lost
* Any other automation that writes to Contact, Opportunity, Payment, or Allocation (Flows, Apex, other vendors). These are the most common source of duplicate or conflicting records after go-live.

### Integration decisions

* Which Salesforce user WeGive will run as (see Phase 1). A dedicated user is strongly recommended.
* Whether to sync Contacts that have no email address (default: no)
* Whether to push events, tickets, and registrations, and which of the four event objects
* Whether to push pledges (requires the pledge custom object; see [Configuration Options](/external/onboarding/salesforce-npsp/configuration-options))
* Sync direction per object: Import, Export, or Both. Defaults suit most orgs; it matters most for Contacts and Opportunities when another system is also a source of truth.
* Which custom fields must map between the systems, by WeGive field, Salesforce API name, direction, and whether create-only. The [Data Mapping Overview](/external/onboarding/salesforce-npsp/data-mapping/overview) and its per-object pages list 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 7.
</Tip>

**Checkpoint 0:** every item above is known or marked not applicable.

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

Work in the Sandbox for Phases 1 through 6.

### 1a. Verify NPSP configuration

Confirm each item in [Setup Requirements](/external/onboarding/salesforce-npsp/setup-requirements#npsp-configuration): Household Account model, RD2 enabled, Household Account and Organization Account record types present, Donation Opportunity record type present, and Middle Name and Suffix enabled on Contact if the org captures them.

If any of these differ from Production, refresh the Sandbox or fix Production first. Validating against a Sandbox that does not match Production proves nothing.

### 1b. Create the integration user

WeGive authorizes as a single Salesforce user. Every record WeGive creates or edits is stamped with that user, and the NPSP trigger exclusions in Phase 3 key off its username. 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 | System Administrator |

    Salesforce appends the Sandbox name to usernames in a Sandbox (for example `wegive@yourorg.org.uat`). Note the full Sandbox username; you will need it for the trigger handler exclusions.
  </Step>

  <Step title="Confirm API access">
    The System Administrator profile includes **API Enabled**. If a custom profile is required instead, it must include API Enabled, Modify All Data, View All Data, Customize Application, and View Setup and Configuration. See [Integration user permissions](/external/onboarding/salesforce-npsp/setup-requirements#integration-user-permissions).
  </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 4 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. If security policy requires profile IP ranges, exempt this user with a dedicated profile.
</Note>

**Checkpoint 1:** you can log in to the Sandbox as the integration user, and NPSP configuration matches Production.

## Phase 2: Install WeGive4SF in the Sandbox

Follow [Installing the WeGive Salesforce Managed Package](/external/onboarding/salesforce-npsp/install-setup/package-install) using the **Sandbox** install link. Choose **Install for All Users**.

After installation:

1. **Setup > Installed Packages** shows **WeGive4SF** with a version number. Record it.
2. **Setup > Permission Sets > WeGive Admin > Manage Assignments**: assign to the integration user.
3. **Setup > Object Manager**: search for "WeGive" and confirm the `wegive__` objects exist.

**Checkpoint 2:** WeGive4SF is listed under Installed Packages and the integration user holds the WeGive Admin permission set.

## Phase 3: External Client App, Remote Site, and trigger exclusions

Follow [External Client App and Connection Setup](/external/onboarding/salesforce-npsp/install-setup/connect-app-setup) sections 1 through 4 exactly, then apply the NPSP trigger handler exclusions on the same page.

Three details trip people up:

* **Activation delay.** A new External Client App can take up to 10 minutes to become usable. Create it first, then do the Remote Site and trigger exclusions while you wait.
* **Sandbox username in exclusions.** In **Usernames to Exclude** on each trigger handler, enter the full Sandbox username including the suffix. In Production you will enter the Production username. A mismatch is silent: NPSP automation simply keeps running on WeGive records.
* **Consumer Secret is shown once.** Store the Consumer Key and Consumer Secret in a password manager immediately. If the secret is lost, generate a new one and re-authorize in WeGive.

**Checkpoint 3:** the ECA exists with the correct callback URL and scopes, the `wegive_api` Remote Site is active, the three trigger handlers list the integration user's full Sandbox username, and the Consumer Key and Secret are stored.

## Phase 4: Connect the WeGive Test dashboard

<Steps>
  <Step title="Sign out of Salesforce">
    Sign out of every Salesforce session in your browser, or use a private window. The authorization step signs in as whoever is currently logged in, and WeGive is bound to that user until you disconnect.
  </Step>

  <Step title="Open integration settings">
    In the WeGive **Test** dashboard: **Settings > Integrations > Salesforce NPSP**, **Connection** tab.
  </Step>

  <Step title="Enter credentials and authorize">
    Paste the Consumer Key into **Client ID** and the Consumer Secret into **Client Secret**, leave **Legacy Username** and **Legacy Password** blank, then click **Save**. Click **Connect with OAuth**. At the Salesforce login, make sure you are on `test.salesforce.com` (or the Sandbox's My Domain) and sign in as the **integration user**. Approve the access request. The header badge should change from **Not connected** to **OAuth connected**.
  </Step>

  <Step title="Test the connection">
    Back on the Connection tab, click **Test Connection**. WeGive verifies API access and reads the org's record types. The **Enable Integration** toggle unlocks only after this test passes.
  </Step>
</Steps>

Leave **Enable Integration** off for now. Configuration comes first. The [Dashboard Settings Reference](/external/onboarding/salesforce-npsp/dashboard-settings) describes every control on this screen.

| Symptom | Likely cause | Fix |
| - | - | - |
| `OAUTH_APPROVAL_ERROR_GENERIC` | ECA not yet activated | Wait 10 minutes and retry |
| `redirect_uri_mismatch` | Callback URL typo in the ECA | Correct it to the value on the connect-app page exactly |
| Environment mismatch error | Test dashboard authorized against Production, or the reverse | Sign out, sign in to the correct org type, authorize again |
| Authorization succeeds but Test Connection fails | Integration user lacks API Enabled or the WeGive Admin permission set | Fix permissions, then click Test Connection again |
| Authorized as the wrong user | A personal Salesforce session was active | Click **Disconnect OAuth**, sign out of Salesforce, re-authorize as the integration user |

**Checkpoint 4:** the header shows **OAuth connected** and Test Connection succeeds.

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

Use the values from Phase 0. Work through the **Sync Configuration** tab top to bottom, then the **Mapping Rules** tab. Every control is described in the [Dashboard Settings Reference](/external/onboarding/salesforce-npsp/dashboard-settings); what each setting means for the data is in [Configuration Options](/external/onboarding/salesforce-npsp/configuration-options).

<Steps>
  <Step title="Core Settings and Entity Pull & Push">
    Under **Entity Pull & Push**, turn on the Pull and Push toggles for the objects decided in Phase 0 and leave the rest off. Leave **Push tag memberships**, **Pull tag memberships**, and **Push payment methods** off unless they were explicitly in scope.

    <Note>
      **Two-way sync and CRM sync are not read by the Salesforce integration.** These dashboard toggles exist on the settings screen but are dead code for Salesforce specifically — confirmed via full-repo grep: neither is referenced anywhere in `Salesforce.php`, `SalesforceIntegration.php`, or `SalesforceOauth.php` (the same column names ARE live and enforced for the Neon CRM integration, which is likely why they still appear in the UI). Leave them at whatever value; they have no effect here. Sync direction is controlled entirely by the per-object Pull/Push toggles below.
    </Note>
  </Step>

  <Step title="WeGive4Salesforce Pushes">
    Enable only the package objects in scope. If enabling events, turn on the four event toggles top to bottom: events, then tickets, then registrations, then registration tickets. See [Events, Tickets & Registrations](/external/onboarding/salesforce-npsp/data-mapping/event).
  </Step>

  <Step title="Deleted Record Sync">
    Leave every toggle off unless the organization has decided that a deletion in Salesforce should remove the record and its history from WeGive.
  </Step>

  <Step title="Contact Sync Options and Sync Schedule">
    Decide whether to keep **Sync contacts with emails only** on. Turning it off imports every Contact in the org on the first pull. Leave **Pull frequency** at its default unless there is a reason to change it.
  </Step>

  <Step title="Stage Names">
    Under **Stage Names, Push**, enter the exact Opportunity Stage the org uses for success, refunded, pending, and failed. Spelling and case must match Salesforce; a mismatch fails every transaction push. Under **Stage Names, Pull**, add any other Stage values that exist on historical Opportunities so they import with the right status. Any Stage that matches nothing imports as failed.
  </Step>

  <Step title="Payment Method Labels">
    Set the card, bank, and PayPal names to match the org's existing Payment Method picklist values.
  </Step>

  <Step title="Record Type Configuration and Opportunity Record Types">
    Enter the record type IDs for tax-deductible donations and service revenue, and confirm the household and non-household record type names match the org (defaults are `Household Account` and `Organization`). Add non-gift Opportunity record types (grants, in-kind, proposals, pledges tracked as Opportunities) to **Hidden Record Types** so they stay out of WeGive.
  </Step>

  <Step title="Processing Options, then Save">
    Turn on **Send processing ACH as success** if the org wants ACH gifts to close in Salesforce before settlement. Turn on **Push both Contact and Account on recurring donations** if the org relies on NPSP household roll-ups for recurring giving. Click **Save** at the top of the tab.
  </Step>

  <Step title="Custom fields in WeGive">
    If custom fields will be mapped, create them first under **Settings > Data & Customization > Custom Fields** on the matching object. A mapping rule can only target a WeGive field that already exists.
  </Step>

  <Step title="Mapping Rules">
    Open the **Mapping Rules** tab. Expand each category and review the default rules for Individuals, Accounts, Households, Opportunities, and Payments. Add custom field rules with **Add Rule** and click that object's **Save**. For each custom Salesforce field confirm the integration user has read and edit field-level access; a rule that targets a field the user cannot see fails the whole record on push. If a field you added in Salesforce is not offered, run **Clear Describe Cache** on the Actions tab.
  </Step>

  <Step title="Pause triggered messages">
    Under **Settings > Communications > Triggers**, turn off every triggered message before enabling the integration. The initial pull imports historical donors and transactions, and a live trigger can send a receipt or welcome email for every one of them. Sandbox addresses are usually invalidated, but you will repeat this step in Phase 7 against real donors.
  </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 7 is a copy exercise.
</Warning>

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

## Phase 6: Validate in the Sandbox

On the **Connection** tab, turn on **Enable Integration**, then click **Sync** to start the first pull without waiting for the schedule. WeGive pushes changes to Salesforce within about five minutes and pulls on the schedule set under Sync Configuration (15 minutes by default), so each test needs a short wait. Run them in order; later tests depend on earlier records. Watch progress and errors under **Settings > Integrations > Integration Logs**.

### 6a. Full data pull

Within about fifteen minutes, Contacts (with emails, if the filter is on), Households, Campaigns, Opportunities, and Recurring Donations from the Sandbox begin appearing in the Test dashboard. Let the pull finish, then reconcile counts:

| Salesforce report | WeGive view | Expected relationship |
| - | - | - |
| Contacts with an email address (or all Contacts, if the filter is off), excluding hidden record types | Donors | Equal, allowing for Contacts WeGive merged as duplicates by email |
| Household Accounts | Households | Equal |
| Closed Won Opportunities with the Donation record type | Transactions with Success status | Equal in count and total amount |
| Active Recurring Donations | Active recurring plans | Equal |
| Active Campaigns | Campaigns | Equal |

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

If nothing appears after thirty minutes, check **Integration Logs** for errors before doing anything else. Records that failed repeatedly appear under **Integration Locks** and stay there until unlocked.

### 6b. Push a new donor 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 donor name and email that does not exist in the Sandbox.
2. Wait five to ten minutes.
3. In the Sandbox, find the Contact by email. Verify:
   * Contact exists, in a new Household Account with the Household record type
   * Opportunity exists with the Donation record type, the correct Amount and Close Date, and the Stage mapped to Success
   * If Uses Payments is on: one Payment record, Paid checked, amount matching the Opportunity
   * If Fund Allocations is on: Allocation records summing to the Opportunity amount, with no unexpected extra allocation to the default GAU (an extra one means `ALLO_Allocations_TDTM` is not excluded for this user)
   * Created By on every record is the integration user
4. Open the donor in WeGive and confirm the Salesforce ID is populated on the donor and the transaction.

### 6c. Push a gift to an existing donor

Make a second test gift using the email of a Contact that already existed in the Sandbox. Verify WeGive matched the existing Contact instead of creating a duplicate, and the new Opportunity landed under the existing Household.

### 6d. Refund

Refund the gift from 6b in the Test dashboard. After the push delay, confirm the Opportunity stage changed to the Refunded stage and the Payment reflects the refund.

### 6e. Recurring gift

Start a monthly test recurring gift. Confirm a Recurring Donation is created in the Sandbox with the correct amount, frequency, and Contact, and that the first installment Opportunity is linked to it.

### 6f. Pull an edit from Salesforce

Edit the phone number on a synced Contact in the Sandbox. Within about fifteen minutes the change should appear on the donor in WeGive. Then edit the same donor's phone in WeGive and confirm it appears in Salesforce. This proves both directions on Contact.

### 6g. Events (if enabled)

Create a test event with one ticket type in the Test dashboard and register a test donor. Confirm `wegive__Event__c`, `wegive__Event_Ticket__c`, and `wegive__Event_Registration__c` records exist and link to each other and to the Contact.

### 6h. Integration log review

Open **Settings > Integrations > Integration Logs** and confirm there are no repeating errors. Check **Integration Locks** is empty, or that every locked record is one you deliberately broke. One-off errors on records you deliberately broke are fine; a repeating error on every push means a configuration problem that will recur in Production.

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

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

Production setup is the same sequence with three differences: the org, the dashboard, and the username.

| Step | Sandbox pass | Production pass |
| - | - | - |
| Integration user | Created in Sandbox | Create in Production (or confirm it exists after a Sandbox refresh from Production). Username has no suffix. |
| Package install | Sandbox install link | Production install link (`login.salesforce.com`) |
| Permission set | Assign WeGive Admin | Assign again; permission set assignments do not deploy |
| External Client App | Created in Sandbox | Create again in Production. A new Consumer Key and Secret are generated. |
| Remote Site | Created in Sandbox | Create again |
| Trigger exclusions | Full Sandbox username | Production username (no suffix). Trigger Handler records are data, not metadata, and do not deploy in a change set. |
| WeGive dashboard | Test | Live, using the Phase 5 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 6a 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 5 setting has been re-entered and reviewed. The first sync pulls the org's history into WeGive and begins pushing WeGive activity into Production. Turning it on with a wrong stage name or record type creates records that must be cleaned up by hand.
</Warning>

### Go-live sequence

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

1. Complete Phases 1 through 5 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, not the days before a major appeal or event. Turn on **Enable Integration** and click **Sync** at the start of the window.
4. Watch the pull. Large orgs can take an hour or more to bring in history. Do not change configuration while it runs.
5. Reconcile counts using the 6a table.
6. Make a small live gift and refund it. Confirm the Opportunity, Payment, and Allocation in Production, then the refund stage.
7. Re-enable triggered messages only after the pull is complete and reconciled.
8. Review Integration Logs and Integration Locks after the first full day and again after the first week.

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

## After go-live

* A Sandbox refresh wipes the Sandbox-side configuration: the ECA, Remote Site, trigger exclusions, and permission set assignment. Re-authorize the Test dashboard after every refresh.
* Record the WeGive4SF version installed in each org. Upgrades install in place using the same links.
* Keep the list of trigger handler exclusions with the org's admin documentation so a future administrator does not remove them.
* The integration user and ECA credentials belong to the organization, not WeGive. Store them accordingly.

## Quick reference: what lives where

| Item | Salesforce Sandbox | Salesforce Production | WeGive Test | WeGive Live |
| - | - | - | - | - |
| WeGive4SF package | Install | Install | | |
| Integration user and permission set | Create, assign | Create, assign | | |
| External Client App and Remote Site | Create | Create | | |
| Trigger handler exclusions | Sandbox username | Production username | | |
| Consumer Key and Secret | | | Enter Sandbox app's | Enter Production app's |
| Sync Configuration and Mapping Rules | | | Configure | Configure again |
| Triggers (Communications) | | | Pause before sync | Pause before sync, re-enable after pull |
| Enable Integration toggle | | | On after Phase 5 | On after Phase 7 review |


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