Skip to main content

Recurring Donation Data Mapping

This document details how WeGive ScheduledDonation records map to DonorPerfect pledges.
Known bug: every WeGive recurring donation syncs to DonorPerfect with a hardcoded frequency = "M" (Monthly), regardless of its actual cadence (weekly, quarterly, semi-annual, annual, 1st-and-15th, etc.). This is a known issue.

DonorPerfect Table Reference

Primary Table: dpgift (record type Pledge, via dp_savepledge) — DonorPerfect doesn’t use a separate dppledge table for this integration; pledges live in the same gift table under a different record type WeGive Model: ScheduledDonation Sync Direction: WeGive → DonorPerfect (Push Only — no pull-back of pledge status or changes)

Core Pledge Fields

Financial Information

Fee handling here is the opposite direction from one-time gifts: a one-time transaction’s dp_savegift subtracts the fee to get a net amount; a pledge’s dp_savepledge adds the fee (only if the donor is covering it) to reflect the total amount actually billed. Don’t assume the same fee-math applies to both.

Fund Attribution

There is no fund/GL code attribution on a pledge at all. syncScheduledDonation()’s gl_code parameter is hardcoded to null unconditionally — unlike syncGift(), it never reads the scheduled donation’s fund. Individual payment transactions linked to the pledge (via syncGift()) do carry their own gl_code, but the pledge record itself carries none.

Schedule and Frequency

Membership and Miscellaneous Fields

syncScheduledDonation()’s full parameter set includes several fields that are always null, regardless of any WeGive data: reminder set to "N", solicit_code, sub_solicit_code, campaign, membership_type, membership_level, membership_enr_date, membership_exp_date, membership_link_id, address_id, ty_letter_no, vault_id, receipt_delivery_g, contact_id, writeoff_date. writeoff_amount is always 0. initial_payment is always "N".
There’s no membership-tracking integration, no campaign attribution, and no writeoff-amount tracking despite these parameters existing in the dp_savepledge payload — they’re always sent as empty/zero placeholders.

Gift Narrative

Same fixed narrative as one-time gifts: "Online gift through WeGive", no pledge-specific variant.

Data Flow Process

  1. syncScheduledDonation() triggers on scheduled-donation create/update (real-time)
  2. If the source donor has no dp_id, exportDonor() runs first
  3. Under a per-scheduled-donation DB lock: if dp_id already exists, the previous DonorPerfect pledge record is fetched and any locally-null param is backfilled from it before sending an update
  4. dp_savepledge is called; on success, dp_id is stored
There is no cancellation-specific handling — a scheduled donation being paused, cancelled, or deleted in WeGive doesn’t trigger any specific pledge-status update in DonorPerfect. The pledge simply isn’t touched again unless the scheduled donation is otherwise updated. There is no pledge_status parameter anywhere in dp_savepledge’s payload.

Payment-to-Pledge Linking

Individual payments link to a pledge via the transaction’s own sync (syncGift()), not the pledge’s sync:
  • pledge_payment is set to "Y" if the transaction has a scheduled_donation_id
  • plink is set to the linked scheduled donation’s dp_id, if that scheduled donation has already synced
If a payment is processed before its scheduled donation has ever synced to DonorPerfect (no dp_id yet), plink is simply null for that payment — there’s no guaranteed ordering that forces the pledge to sync first. The pledge does eventually get its own dp_id from its own independent sync trigger, but a specific payment might race ahead of it.

Error Handling

Same as every other DonorPerfect sync path: no automatic retry, no exponential backoff. A failed dp_savepledge call is reported to Sentry (via Undefined id/general exception paths) and the scheduled donation is left without a dp_id until the next update triggers another attempt.

API Operations

dp_savepledge

See the full parameter breakdown above — every field not explicitly listed as WeGive-derived is a fixed placeholder (null, "N", or 0).

Data Quality Considerations

Before Sync

  • Understand that pledge frequency will show as Monthly in DonorPerfect regardless of the real schedule (known issue) — factor this into any DonorPerfect-side reporting expectations until that’s fixed
  • Don’t rely on the pledge record for fund/GL code reporting — that lives only on the individual linked payments

Ongoing Maintenance

  • Check Sentry (not the WeGive dashboard) for dp_savepledge failures

Known Limitations

  • Frequency: always “Monthly” regardless of actual cadence (known issue)
  • Fund attribution: none on the pledge itself
  • No pledge-status sync: pause/cancel/resume in WeGive doesn’t push any corresponding status change to DonorPerfect
  • No pull-back: pledge changes made directly in DonorPerfect never flow back to WeGive
  • No membership or campaign data: fields exist in the payload but are always empty placeholders

Troubleshooting

Pledges Not Creating

Possible causes:
  • The integration is disabled
  • The donor sync (triggered inline first) failed
  • API authentication failure
Solutions:
  • Confirm the integration’s enabled flag
  • Check Sentry for the specific failure

Payments Not Linking to Pledges

Possible cause: The scheduled donation hasn’t synced yet (no dp_id) at the moment the payment itself synced — plink will be null for that payment permanently; it isn’t retroactively backfilled.

Pledge Shows Wrong Frequency

Cause: Known bug, not a misconfiguration.

Transaction Mapping

How individual payments link to pledges

Donor Mapping

Donor record requirements for pledges

Fund Management

GL code setup (used by individual payments, not by pledges themselves)

Configuration Guide

Integration-level configuration (most sync-scope toggles are currently non-functional)
For additional help with recurring donation mapping, contact our support team at [email protected].