Campaign Object Mapping
This document details the real mapping used byNeonIntegration::generateCampaignParams() (push) and SyncNeon::importCampaigns() (pull).
Core Campaign Mapping (Push)
URLs use the organization’s real donor-portal base URL (
donorPortalBaseUrl()), not a hardcoded app.wegive.com — the actual domain varies by organization (custom domains are supported).Statistics — Pull Behavior Is Much Narrower Than It Looks
Status Mapping
Status Synchronization
- Push: deleted campaigns push as
INACTIVE - Pull:
importCampaigns()skips any Neon campaign withstatus == 'INACTIVE'entirely — it’s not imported at all, not even as an inactive WeGive campaign - There is no WeGive-side reactivation flow driven by a Neon-side status flip back to
ACTIVE— since pull never updates existing campaigns (see above), a status change in Neon on an already-imported campaign has no effect on the WeGive record either way
Custom Field Mapping
The default seededNeonMappingRule records for campaigns include statistics fields (statistics.donationAmount → total_donated, etc.) — but since importCampaigns() doesn’t consult NeonMappingRule at all (same as every other Neon object type on pull), these defaults have no effect. This is a known issue.
Adding Custom Mappings
Synchronization Behavior
Campaign Creation/Update (Push)
- If
neon_idalready set →PUT /campaigns/{neon_id}(update); otherwise →POST /campaigns(create) - There is no name-uniqueness check or duplicate-prevention logic performed by WeGive before push — any rejection would come from Neon’s own API
Import from Neon CRM (Pull)
GET /campaigns— a flat, unfiltered list fetch, not a search/pagination call- Skip any campaign with
status == 'INACTIVE' - If no WeGive
Campaignexists with a matchingneon_id, create a new one with justnameandneon_id— goal, dates, and status are not set on the newly created WeGive campaign either, only on the Neon side of the relationship - If a matching campaign already exists, nothing happens — no field is ever updated on subsequent pulls
Campaign-Donation Relationship
- Donation push includes
campaign.id/campaign.name/campaign.statusonly if the campaign already has aneon_id— there is no “sync the campaign first if it’s missing” orchestration inside donation push. A donation for an unsynced campaign simply pushes withcampaign: null. - Recurring-donation push has no campaign field at all — see Recurring Donation Mapping
Error Handling
API Examples
Creating a Campaign (real payload shape)
No
statistics, fund, purpose, parentCampaign, or socialFundraising keys are sent — confirmed absent from the real payload. The base URL reflects the organization’s own donor-portal domain, not a fixed WeGive domain.Fetching Campaigns (Pull)
This is a flat list fetch with no search filters or pagination parameters — unlike donor/donation pull, which use
POST .../search with date filters. A large Neon account with many campaigns would return them all in one call.Best Practices
- Don’t expect campaign statistics (donation totals, pledge counts) to ever appear on the WeGive side via this integration — they’re Neon-only data that never gets pulled in
- Don’t expect a campaign edit made in Neon (renaming, changing goal/dates) to propagate back to WeGive — pull only creates, never updates
- If a campaign needs its goal/dates corrected on both sides, make the change directly in WeGive and let it push — don’t rely on Neon as the source of truth for anything beyond the initial name