DonorPerfect Integration Nuances
Understanding the specific behaviors and limitations of the DonorPerfect integration will help you avoid common issues.Platform-Specific Behaviors
DonorPerfect API Characteristics
XML-Over-HTTP Communication
XML-Over-HTTP Communication
Legacy API FormatDonorPerfect’s
xmlrequest.asp endpoint is called via a single GET request per action, with the action and params encoded directly into the query string. Responses are XML; WeGive parses them with simplexml_load_string. There’s no JSON option.SQL-Style Query Interface
SQL-Style Query Interface
Direct Query AccessPull operations use literal SQL-style
select * from dpgift where .../select * from dp where ... strings built directly into the request — not a REST-style filtered endpoint. This is genuinely how DonorPerfect’s API works for this integration, not an abstraction WeGive built.No Rate Limiting or Retry Logic
No Rate Limiting or Retry Logic
Contrary to what you might expectThere is no rate-limit handling, throttling, or automatic retry anywhere in this integration’s code. Every API call (
makeRequest()) is a single unretried HTTP GET with a 120-second timeout. A failed call is reported to Sentry and the record it was attempting to sync is simply skipped for that run.Data Format Requirements
Date Formatting
There’s no donor birth-date field mapped at all in this integration —
exportDonor() doesn’t send one.Currency Handling
Amount Conversion (WeGive → DonorPerfect):- Gift amount:
(transaction.amount - transaction.fee) / 100— fee is deducted before the cents-to-dollars conversion, not just before sending - Pledge amount:
(scheduled_donation.amount + optional fee_amount) / 100
currency value is sent as-is on gift sync (@currency param) — there’s no currency conversion, exchange-rate handling, or USD-only restriction in the code. Whether DonorPerfect’s UI displays a non-USD value meaningfully is outside WeGive’s control.
Text Fields
There is no character-limit truncation logic anywhere in
DonorPerfectIntegration.php — no substr, Str::limit, or similar. If DonorPerfect’s own API rejects an over-length field, that shows up as a sync failure (reported to Sentry), not a silent truncation.Synchronization Behaviors
Incremental Pull Logic
- Pull queries filter on
created_datethenmodified_dateas two separate passes, each starting fromid > 0and paging forward by recursing with the last-seen id as the new floor — not true pagination with page numbers - A DonorPerfect row is skipped (not partially synced) if: its email is missing/invalid (donors), or its
amountis0/'0'(gifts) - Records already recognized as WeGive-originated (via
user_id = 'WeGive'or aWG:txn:reference prefix) are skipped on pull — this prevents WeGive from re-importing its own pushes as new records
Push Logic
- Donor/gift/pledge push is triggered by the model being created or updated in WeGive — this part is genuinely real-time
- A push with no existing
dp_idcreates a new DonorPerfect record; a push with an existingdp_idupdates it - All pushed records are stamped
user_id = 'WeGive'for tracking and later dedup
Duplicate Handling
The only dedup mechanism is DonorPerfect ID (dp_id)-based:
- Import skips a gift already recorded against a donor with that exact
dp_id - A WeGive-originated gift is recognized by
user_id/reference prefix, not by amount/date matching - There’s a specific phantom-gift recovery path: if a
dp_savegiftpush returns a 2xx response with noidfield, the integration looks up the gift by its WeGive reference token before retrying, to avoid creating duplicate gift records on a lost-response retry — see the dedicated duplicate-gift-import doc for the full mechanics
There is no email-based or name-based duplicate donor detection — only
dp_id correlation. A donor pushed before being matched to an existing DonorPerfect person will always create a new one.Field Mapping Limitations
Hardcoded Values
Missing Field Support
Fields that don’t sync to DonorPerfect:- Custom donor profile fields (no custom-field mechanism exists at all)
- Detailed payment method data (card type, last-4, etc.) — DonorPerfect gets amount/date/reference only
- Middle name, suffix, title, salutation — all sent as
nullon push (see the donor data-mapping page) - Campaign attribution of any kind
- Fund goal amount, category, hierarchy
- Volunteer tracking, relationship/household data
- Custom code tables
Performance Considerations
Large Database Handling
Organizations with large DonorPerfect databases should expect longer initial pull times — the pull recurses through records via ascending id, one page of results per API call, with no configurable batch size.There is no automatic batch-failure retry, no automatic memory-management optimization, and no real-time dashboard progress indicator specific to this integration beyond the generic pull-progress tracking shared by all WeGive CRM integrations (visible as overall pull status, not DonorPerfect-specific detail).
Best Practices
Data Preparation
1
Clean Existing Data
Remove duplicate donors before initial sync — there’s no automated dedup beyond
dp_id correlation2
Validate Email Addresses
Donors without a valid email are silently skipped on every pull, not just the first one
3
Set Up GL Codes First
A fund needs a
dp_id (via syncFund(), which only fires automatically the first time a gift references that fund) before gift-fund attribution worksOngoing Management
- Check Sentry (not the WeGive dashboard) for DonorPerfect sync failures — there’s no customer-facing sync-status view for this integration
- If a transaction later fails after already syncing successfully to DonorPerfect, resyncing from WeGive cannot correct it (the sync payload carries no status field) — see the dedicated status-field doc
Common Limitations
- Recurring frequency: every WeGive recurring donation syncs to DonorPerfect as
"M"(Monthly), regardless of its actual frequency - No fund pull: funds only push (GL code, one-way); DonorPerfect-side fund changes never flow back
- No campaign sync: none at all, despite a dashboard toggle suggesting otherwise
- Single currency assumption in UI messaging only: the code itself passes through whatever currency the transaction has; multi-currency correctness on DonorPerfect’s side is not something WeGive verifies
Troubleshooting Common Issues
API Authentication Errors
API Authentication Errors
Symptoms: DonorPerfect returns an
<error> element in its response body (DP returns HTTP 200 even on logical errors)Solutions:- Verify the API key is correct and active
- Check the API key’s permissions in DonorPerfect directly
Missing/Skipped Donors
Missing/Skipped Donors
Symptoms: A DonorPerfect donor never appears in WeGive after pullSolutions:
- Check the donor has a valid, present email in DonorPerfect — this is a hard skip condition, not a warning
Duplicate-Looking Gift Records
Duplicate-Looking Gift Records
Symptoms: Two WeGive transactions both reference DonorPerfect, but only one gift is visible in DonorPerfectSolutions:
- This usually indicates the two
dp_ids were genuinely distinct at sync time, and one was later merged/deleted in DonorPerfect itself — not a WeGive-side import bug. See the dedicated duplicate-gift diagnosis doc for the full runbook.
Next Steps
Data Mapping Reference
Detailed field mapping documentation
Get Support
Contact our team for integration assistance