Skip to main content

Recurring Donation Object Mapping

This document details the real mapping used by NeonIntegration::generateRecurringDonationParams(). Recurring donation sync is push-only — there is no pull for recurring donations at all.
Frequency mapping is broken, not just narrow. recurringPeriod is sent as $scheduledDonation->iteration — but iteration is a live-computed count of successful charges this plan has been through (getIterationAttribute(): (int) $this->transactions()->success()->count()), not a frequency value. This means recurringPeriod changes every single time the plan is charged (1, 2, 3…) and has no relationship whatsoever to the plan’s actual cadence. WeGive’s real frequency field (ScheduledDonation::frequency — monthly/weekly/quarterly/etc.) is never read or sent anywhere in this integration. This is a known issue — high priority, unlike the other Neon findings in this audit, since this produces actively wrong, changing data for every synced org today (not a dormant/deprecated-integration concern).

Core Recurring Donation Mapping

There is no currency field sent — no USD default, no currency key at all.
Campaign, fund, purpose, and end date are all commented-out placeholders in generateRecurringDonationParams() — none are ever populated, despite Neon’s API supporting all of them. A recurring donation’s campaign attribution and any end-date/limited-term configuration never reaches Neon.

Integration Fields

Custom Field Mapping

Unlike accounts and donations, there is no seeded default NeonMappingRule set for recurring donations in this integration — the hardcoded fields above are the entirety of what’s sent, with no custom-mapping override path exercised in the code shown for this object type.

Synchronization Behavior

Recurring Donation Creation/Update (Push)

  1. If neon_id already set → PUT /recurring/{neon_id} (update); otherwise → POST /recurring (create)
  2. There is no “verify donor account/payment method first” orchestration inside recurring-donation push itself — if the donor’s neon_account_id isn’t set, the push simply sends accountId: null
  3. There is no distinct status/pause handling sent to Neon — a paused or ended WeGive plan doesn’t push a corresponding status change to Neon; Neon simply keeps receiving whatever nextDate/amount/(broken) recurringPeriod the plan currently has whenever it’s next pushed
There is no automatic retry. A failed push simply fails — check Sentry for the specific Neon API error.

No Pull

There is no pull for recurring donations — SyncNeon.php has no pullRecurringDonation()/importRecurringDonations() method. Recurring donations created or edited directly in Neon never flow back to WeGive.

API Examples

Creating a Recurring Donation (real payload shape)

recurringPeriod: 0 here reflects a brand-new plan with zero successful charges yet — not a “period of zero” in any meaningful sense. After the plan’s first successful charge, the next push of this same plan would send recurringPeriod: 1; after the second charge, 2; and so on, unrelated to actual cadence.

Updating a Recurring Donation

Error Handling

There is no automatic retry, amount validation, or schedule-feasibility validation performed by WeGive for recurring-donation push. A failed push simply fails.

Best Practices

  • Don’t rely on Neon’s recurringPeriod field for this integration’s data to reflect a donor’s actual giving cadence today — it doesn’t, pending a known issue being fixed
  • Understand there’s no campaign/fund attribution on recurring donations reaching Neon at all — if campaign-level recurring revenue reporting matters, it isn’t available via this path
  • There’s no pull, so any recurring-plan edit made directly in Neon won’t flow back — make plan edits in WeGive