Skip to main content

Data Mapping Overview

This page describes what actually syncs between WeGive and Neon CRM, and how.
Sync direction below is described per object, not per field — see the individual data-mapping pages for the field-level detail. “Bidirectional” object-level sync does not mean every field mapping is bidirectional; in fact, none currently are (see the Custom Field Mapping section below).

Core Object Mappings

There is no separate “Payment” object mapping distinct from Donation — a Neon donation carries its own nested payments array in the same request, not a separate synced entity.

Neon Object Details

Individual/Company Account

What’s real: first/last name (or company name), up to 3 email addresses, email/SMS consent flags, mailing and (for individuals) billing address (inline, no phone/fax fields). See the warning below re: address/phone.
There is no login-credential creation, “no solicitation” flag control, or origin-tracking beyond a fixed "WeGive" origin string that’s actually implemented meaningfully — login.password is hardcoded to a fixed literal password ('WeGiveTest1234') for every donor across every organization, and noSolicitation is always sent as false. Neither is configurable per donor. The hardcoded shared password is a known issue (low priority — WeGive currently has no active customer on this integration).

Donation

What’s real: amount (fee-adjusted), date, donor account reference, campaign reference (if any), anonymous flag, donor-covered-fee amount, tribute name, and a nested payment (tender type, card/bank detail, last-4 digits).
There is no “payment processor information” beyond what’s described above, and no fund/purpose object mapping — Neon supports a fund/purpose field on donations, but this integration never populates it (commented out in the payload-generation code).

Campaign

What’s real: name, start/end date, goal, active/inactive status, generated campaign page and donation form URLs (push); statistics (donationAmount, donationCount, eventRegistrationAmount, eventRegistrationCount, grandTotal) computed by Neon and read on pull.
There is no campaign description, campaign hierarchy (parent/child), or fund/purpose association implemented — all exist as commented-out fields in the payload-generation code, not working features.

Recurring Donation

What’s real: amount, next payment date, and a recurringPeriod/recurringPeriodType pair — push only, create/update, no pull.
recurringPeriodType is always "LIFE". There is no campaign, fund, purpose, or end-date mapping for recurring donations — all commented out in the code. See the dedicated Recurring Donation Mapping page for the frequency/period detail.

Address

Dead code. syncAddress()/generateAddressParams() are fully implemented but never called anywhere in the codebase — no pushAddress() entry point exists on Neon.php. Address sync has never actually run for any organization. This is a known issue.
What would be real if this were wired up: address lines, city, zip, and phone numbers — push only, no pull. What’s actually real today: a stripped-down inline address copy (no phone) within the donor account push — see Account Mapping.

Default Field Mappings

Account/Donor Mapping (all fields below are push-only in practice — see the warning further down)

Individual Donor → Individual Account

Company Donor → Company Account

There is no separate company-specific email/phone field distinct from what’s already listed for individual donors — company donor pushes reuse the same primaryContact structure (with firstName sent as null).

Transaction/Donation Mapping

Transaction amount for donations is not fee-adjusted the way DonorPerfect’s gift-amount is — generateDonationParams() sends amount / 100 directly (the full transaction amount), and donorCoveredFee is reported as a separate field alongside it, not subtracted from amount.

Payment Method Mapping

Only card, bank, and donor are mapped source types, all falling back to Check for anything unmapped. There is no distinct Cash, Stock/Securities, In-Kind, PayPal, Wire, or Gift Certificate tender type ever sent by this integration, despite Neon CRM supporting all of these as a platform.

Card Type Mapping

Any other card issuer has no code mapped at all — the lookup returns null/undefined for cardTypeCode.

Campaign Mapping

The registration-related statistics fields exist as seeded NeonMappingRule defaults, but since Neon’s field-application code doesn’t consult NeonMappingRule on pull at all (see below), and importCampaigns()’s own hardcoded fetch pulls id/name/status only — none of the statistics fields are actually populated on pull today, contrary to what the seeded defaults would suggest. This is a known issue.

Address Mapping

The table below describes generateAddressParams()’s field mapping for reference — but this code path is never invoked (known issue). The address data that actually reaches Neon today is the smaller inline copy on the account push — see Account Mapping.
There’s no country-code mapping in this (unreachable) code either — generateAddressParams() doesn’t populate a country field at all.

Custom Field Mapping System

JSONPath-based mapping is real, via NeonMappingRule:

Supported Objects

NeonMappingRule::integration accepts: ACCOUNT (1), DONATION (2), CAMPAIGN (3), RECURRING_DONATION (4), ADDRESS (5) — same shared enum used by other CRM integrations’ mapping rules (values 6-10 are used by other CRMs, not Neon).
Every default and custom NeonMappingRule is push-only in practice, regardless of its level value. generateAccountParams()/generateDonationParams() (both push functions) are the only code that ever reads NeonMappingRule — SyncNeon’s pull methods (importDonors(), importDonations(), importCampaigns()) use their own separate hardcoded field lists and never consult NeonMappingRule at all. A rule configured with level = 'import' or 'both' has no pull-side consumer. This is a known issue.
The literal flag (meant to send a fixed value instead of resolving wegive_path as JSONPath) is not honored by Neon’s field-application code. This is a known issue, with a fix in review.

Data Synchronization Rules

Correlation IDs

  • neon_account_id — Neon account id (donors)
  • neon_id — Neon contact id (donors), or Neon donation/recurring-donation/address/campaign id depending on the model
  • neon_payment_id — Neon payment id (transactions only)

Matching Logic (push)

  1. Correlation id (neon_account_id/neon_id) if already set → update
  2. No correlation id → create; on Neon’s 10012 (duplicate) error, search by email and link the existing account instead of retrying create
  3. There is no name+organization fallback matching — only the email-search-on-duplicate-error path above

Matching Logic (pull)

  1. Email exact match against an existing WeGive User
  2. No match → create a new Donor + User + Login
  3. There is no “last modified wins”/field-level conflict resolution mechanism — pull simply overwrites the mapped fields it fetched; push simply sends whatever WeGive currently has. There’s no timestamp comparison deciding which side “wins.”

API Endpoint Reference

WeGive Dashboard API (real, authenticated)

  • GET /neon-integration — retrieve settings
  • PUT /neon-integration — update settings
  • POST /neon-integration/sync — trigger manual sync
  • POST /neon-mapping-rules — create/update mapping rules
  • DELETE /neon-mapping-rules/{neon_mapping_rule} — remove a mapping rule
There is no public /donors, /transactions, /campaigns, /scheduled-donations REST API surface specific to this integration — those are general WeGive dashboard/public API endpoints, not integration-specific routes.

Neon CRM API (real, called by this integration)

  • POST /accounts/search, POST /accounts, PUT /accounts/{id}, GET /accounts/{id}
  • POST /donations/search, POST /donations, PUT /donations/{id}
  • GET /campaigns, POST /campaigns, PUT /campaigns/{id}
  • POST /recurring, PUT /recurring/{id}
  • POST /addresses, PUT /addresses/{id} — implemented in code (generateAddressParams()) but never actually called; this is a known issue
  • POST /webhooks, GET /webhooks, DELETE /webhooks/{id}
There is no GET /accounts (list-all), GET /donations/{id} (single-get outside the linkDonorFromResponse helper), or GET /addresses/GET /recurring used anywhere in this integration’s code.

Integration Notes

Validation

  • Neon donor pull requires a non-blank email — a missing/invalid email skips the row entirely
  • There is no ISO 8601 enforcement, phone-number normalization, or amount/currency format validation performed by WeGive — values are sent as-is; any rejection surfaces as a Neon API error

Performance

There is no rate limiting, batching optimization, or automatic retry in this integration. Every API call is a single unretried Http::timeout(120) request.