> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wegive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Mapping Overview

> Comprehensive overview of how data is mapped and synchronized between WeGive and DonorPerfect systems.

# DonorPerfect Data Mapping Overview

The WeGive DonorPerfect integration maps a fixed, hardcoded set of fields between the two systems — there is no customer-configurable field mapping and no custom-field support.

## Integration Architecture

### Data Synchronization Types

**Pull Operations (DonorPerfect → WeGive):**

* Import donor profiles (email-required)
* Import gift/transaction records
* Runs once daily, incrementally by `created_date` then `modified_date`

**Push Operations (WeGive → DonorPerfect):**

* Create/update donor profiles
* Create/update gift records
* Create/update recurring-gift pledges (push-only, no pull-back)
* Create GL codes for funds (push-only, no pull-back)
* Push happens as each WeGive record is created or updated — this part is genuinely real-time

<Note>
  There is no Campaign data of any kind pulled or pushed by this integration.
</Note>

## Core Data Entities

The integration handles four object types:

### Donors (Individuals & Organizations)

**DonorPerfect table**: `dp`

Maps a fixed set of contact fields (name, email, phone, address) — see [Donor Mapping](/external/onboarding/donorperfect/data-mapping/donor) for the exact list. No custom fields, donor classification/preference data, or communication-preference fields are mapped.

### Transactions (Gifts)

**DonorPerfect table**: `dpgift`

Synchronizes gift amount, date, fund/GL code, and a fixed set of tribute/narrative fields. See [Transaction Mapping](/external/onboarding/donorperfect/data-mapping/transaction).

### Recurring Donations (Pledges)

**DonorPerfect table**: `dpgift` (record type `Pledge`, via `dp_savepledge`) — push-only

See [Recurring Donation Mapping](/external/onboarding/donorperfect/data-mapping/recurring-donation).

### Funds (GL Codes)

**DonorPerfect table**: `dpcode` — push-only

See [Fund Mapping](/external/onboarding/donorperfect/data-mapping/fund).

## Data Transformation Rules

### Format Conversions

| Data Type | WeGive Format | DonorPerfect Format | Transformation |
| - | - | - | - |
| **Amounts** | Integer (cents) | Decimal (dollars) | `(amount - fee) / 100` for gifts |
| **Dates** | Timestamp | MM/DD/YYYY | `->format('m/d/Y')` |

<Note>
  There is no phone-number cleaning, address standardization, or name-length truncation logic anywhere in this integration — values are sent and received as-is.
</Note>

### Field Validation Rules

**Donor pull (`importDonor()`):**

* A DonorPerfect row missing an `email` key, with an empty email, or one that fails `filter_var(..., FILTER_VALIDATE_EMAIL)` is **skipped entirely** — this is the only real validation gate
* Matching to an existing WeGive `User` is by exact email string match

**Gift pull (`importGift()`):**

* A gift with `amount` of `0`/`'0'` is skipped
* A gift already recognized as WeGive-originated (`user_id = 'WeGive'` or a `WG:txn:` reference prefix) is skipped
* A gift matching an already-known `dp_id` for that donor is skipped

## Identity Management

* **Donors**: `dp_id` is the only correlation key. There is no email or name matching used to link an existing DonorPerfect donor on push — a donor without a stored `dp_id` will always create a new DonorPerfect person.
* **Gifts**: `dp_id` correlation, plus a `WG:txn:<transaction id>` reference token stamped on every WeGive-originated gift. This reference token is used for a specific recovery mechanism: if a gift push returns a 2xx response with no `id` field (DonorPerfect may still have created the record), the integration looks up the gift by this reference token before retrying, to avoid creating duplicate gift records.
* **Funds**: `dp_id` correlation (set to the WeGive fund's own numeric id, not a value returned by DonorPerfect).

## Data Enrichment

The only "enrichment" this integration performs:

* A fixed gift narrative: `"Online gift through WeGive"`, with `" (Anonymous)"` appended for anonymous transactions
* Every pushed record stamped `user_id = "WeGive"` — this doubles as both an audit marker and the mechanism that prevents re-importing WeGive's own pushes as new pull records

## Synchronization Timing

**Push (real-time):** Donor, gift, pledge, and fund pushes happen as the corresponding WeGive record is created or updated.

**Pull (once daily):** Donors and gifts are pulled once per day, via two incremental passes (`created_date` then `modified_date`), paging forward by donor/gift id.

<Warning>
  There is no 15-minute incremental schedule, no separate weekly bulk-operation schedule, and no configurable batch size — pull runs exactly once daily with a fixed query shape.
</Warning>

## Error Handling and Recovery

<Warning>
  There is no auto-correction, automatic retry, or configurable duplicate-merge logic in this integration. A failed API call is a single unretried request — the failure is reported to Sentry, and that specific record is skipped for the current run.
</Warning>

| Error Type | What Actually Happens |
| - | - |
| **DonorPerfect logical error** (DP returns HTTP 200 with an `<error>` element) | Reported to Sentry via a single chokepoint (`responseError()`); the calling method still has to decide how to proceed |
| **Missing/invalid email (pull)** | Donor row skipped entirely, silently |
| **Zero-amount gift (pull)** | Gift row skipped entirely, silently |
| **Unresolvable fund (push)** | Not explicitly guarded in `syncGift()` — the GL code param is simply left null/absent if the fund has no `dp_id` yet |
| **2xx response, no `id` (push)** | Reference-token lookup recovery (see Identity Management above); throws `'Undefined id'` only if that recovery also fails |

### Monitoring

<Warning>
  There is no sync-status dashboard, error-rate tracking, performance-metrics view, or automated email-alert system for this integration. The only visibility into sync failures is Sentry — support has to check there directly, not the WeGive dashboard.
</Warning>

## Best Practices

### Before Integration

1. Clean duplicate donor records in DonorPerfect — WeGive's own dedup is `dp_id`-only, so pre-existing DonorPerfect-side duplicates aren't resolved by this integration
2. Ensure donor emails are present and valid in DonorPerfect — an invalid/missing email means that donor never imports
3. Set up GL codes in DonorPerfect before enabling push, since a fund without a `dp_id` doesn't attribute a gift's GL code cleanly

### Ongoing Maintenance

* Check Sentry (not the WeGive dashboard) for sync failures
* Review the field-mapping pages below for the exact, fixed set of fields synced — there's no way to add more without an engineering change

## Detailed Mapping Documentation

<CardGroup>
  <Card title="Donor Mapping" href="/external/onboarding/donorperfect/data-mapping/donor">
    Complete field mapping for donor profiles
  </Card>

  <Card title="Transaction Mapping" href="/external/onboarding/donorperfect/data-mapping/transaction">
    Detailed transaction and gift field mapping
  </Card>

  <Card title="Recurring Donations" href="/external/onboarding/donorperfect/data-mapping/recurring-donation">
    Pledge synchronization (push-only)
  </Card>

  <Card title="Fund Management" href="/external/onboarding/donorperfect/data-mapping/fund">
    GL code mapping (push-only)
  </Card>
</CardGroup>

## Support

For questions about data mapping, contact our support team at [support@wegive.com](mailto:support@wegive.com). Custom field mappings are not currently supported for this integration.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.