Skip to main content

Data Mapping Overview

This document provides an overview of how the WeGive donor platform maps to Planning Center’s People and Giving modules. The real mapping is narrower than a generic CRM sync — a handful of fields per object, no custom fields, no household/family sync, and no recurring-gift sync.

Object Mapping Categories

The integration maps objects across two Planning Center modules:
  1. People Module — Person, plus embedded email/phone/address contact info
  2. Giving Module — Donation, Batch, Fund, PaymentSource, Designation
There is no Planning Center RecurringGift sync in this integration — pushTransaction() (the only place a Transaction touches the API) is a literal no-op; Planning Center recurring gifts are only ever read incidentally as a correlation reference on pulled donations, never pushed or independently synced.

Core Object Mappings

People Module Mapping

Giving Module Mapping

Planning Center Object Details

Person Object

Fields actually synced:
  • first_name, last_name (falls back to literal "FNU"/"LNU" if blank on push)
  • Up to 3 emails (position-based: email_1/email_2/email_3)
  • Up to 2 phone numbers (position-based: mobile_phone/office_phone)
  • One mailing address
  • status (pulled only, maps to the donor’s enabled flag)
There’s no birthdate, anniversary, gender, middle-name-on-pull, suffix, or household/family-relationship mapping. Middle name is pushed but not pulled back.

Donation Object

Fields actually synced:
  • amount_cents, payment_method (card or ach, from the transaction’s source_type), received_at/created_at, person_id
  • Exactly one Designation (fund + amount) per donation — split/multi-fund gifts aren’t supported

Batch Object

  • description — the batch’s own display name, format WeGive Import MM/DD/YYYY
  • Batches are found-or-created once per push run (one batch per day, not one per donation) and auto-committed after processing

Fund Object

Fields actually synced:
  • name (push and pull), description (push on create only, pull), visibility (push always sets everywhere; pull’s hidden value soft-deletes the WeGive fund)
  • color_identifier is set to a fixed value of 1 on create, never read back
No fund goal amount, category, hierarchy/parent-child structure, is_active/active-status sync, or analytics fields are mapped — WeGive’s funds.active column exists but isn’t pushed to or read from Planning Center at all.

PaymentSource Object

A single Planning Center payment source named “WeGive” is found or created once and reused for every transaction — there’s no per-payment-method or per-organization payment source.

WeGive Object Mappings

Donor ↔ Person

Transaction ↔ Donation

Push side note: a pulled donation whose transaction has a correlation_id (WeGive-processed payment) or is still future-dated-pending keeps its WeGive-owned amount/allocations — a Planning Center-side edit doesn’t overwrite the real payment amount (this is a guarded, fixed behavior, not an open issue).

Fund ↔ Fund

Data Synchronization Rules

Correlation ID Management

  • planning_center_id is the only matching mechanism, on every object type (Donor, Fund, Transaction)
  • There is no email-based or name-based matching fallback anywhere in this integration
  • A push targeting a planning_center_id that returns 404 (record deleted externally) clears the stale ID and creates a new record instead of failing

Sync Direction Rules

Push (WeGive → Planning Center): creates or updates by planning_center_id; existing Planning Center Person/Donation records are updated on push, but an existing Fund match is left untouched after initial creation (no update path). Pull (Planning Center → WeGive): creates or updates WeGive records by planning_center_id; pull always overwrites the local record’s mapped fields, with the one carve-out above for transactions already owned by a WeGive-processed payment.

API Endpoint Reference

Planning Center API Endpoints Actually Used

  • people/v2/people, and per-person nested emails/phone_numbers/addresses (via the insert/update helper methods)
  • giving/v2/batches, giving/v2/donations, giving/v2/payment_sources, giving/v2/funds
There is no giving/v2/recurring_gifts write path used by this integration — recurring gifts are only referenced as a read-only relationship ID on a pulled donation.

Integration Notes

Data Validation

  • Planning Center requires a name — WeGive substitutes "FNU"/"LNU" placeholders rather than failing when both first and last name are blank
  • A transaction with a non-positive amount is silently skipped on push (Planning Center requires positive amounts)
  • A transaction that can’t resolve any fund (no fund link, no default_fund_id, no fallback fund) throws Unknown Fund Source and is skipped — logged to Sentry, not surfaced to the customer

Performance Considerations

  • Transactions sync exclusively through the once-daily 8:01 AM batch job — there’s no real-time transaction push
  • Donor and fund pushes happen in real time as part of the batch build (pushDonor()/pushFund() called inline per transaction)
  • Pulls (donors, funds, transactions) run on a separate once-daily schedule with no fixed time
  • API calls are throttled to Planning Center’s real limit (70 requests / 20 seconds) via a hardcoded internal counter, not a configurable setting

Known Gaps (not implemented)

  • Household/family relationship sync
  • Recurring/scheduled-gift sync
  • Custom fields
  • Multi-fund/split-designation support
  • Fund goal, category, hierarchy, or activity-status sync
  • Performance/monitoring telemetry of any kind