> ## 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.

# Transaction Data Mapping

> Detailed field mapping for transactions and gifts between WeGive and DonorPerfect systems.

# Transaction Data Mapping

This document details how one-time WeGive transactions map to DonorPerfect gift records. This is a fixed field set — there is no configurable mapping and no automatic retry.

## DonorPerfect Table Reference

**Primary Table**: `dpgift` (Gift Records)
**WeGive Model**: `Transaction`
**Sync Direction**: WeGive → DonorPerfect (Push Only)

## Core Transaction Fields

| WeGive Field | DonorPerfect Field | Notes |
| - | - | - |
| `dp_id` | `gift_id` | The correlation key; empty on first push (create), set on subsequent (update) |
| `owner.dp_id` | `donor_id` | Donor must already be linked — `syncGift()` triggers `exportDonor()` first if `owner.dp_id` is null |
| — | `record_type` | Always `"G"` |
| — | `user_id` | Always `"WeGive"` |

<Note>
  Unlike other WeGive CRM integrations, there's no explicit auto-create-donor-then-retry-transaction recovery here — `syncGift()` simply calls `exportDonor()` synchronously first if needed, as part of the same request, not as an error-recovery retry.
</Note>

## Financial Information

### Amount Processing

| WeGive Field | DonorPerfect Field | Calculation |
| - | - | - |
| `amount`, `fee` | `amount` | `(amount - fee) / 100` — fee is deducted **before** the cents-to-dollars conversion |
| `destination.currency` | `currency` | Sent as-is, no conversion or validation |

<Note>
  There's no currency code validation or exchange-rate conversion in the code — whatever the transaction's `currency` value is gets sent directly.
</Note>

### Date

| WeGive Field | DonorPerfect Field | Format |
| - | - | - |
| `created_at` | `gift_date` | `MM/DD/YYYY` via PHP's `->format('m/d/Y')` |

## Fund Attribution

| WeGive Field | DonorPerfect Field | Notes |
| - | - | - |
| `fund.dp_gl_code` | `gl_code` | The fund's `dp_gl_code` column — **not** the same value used to create the fund's own GL code in DonorPerfect (see [Fund Mapping](/external/onboarding/donorperfect/data-mapping/fund) for that distinction) |

<Warning>
  `syncFund()` is triggered inline (before the gift itself) if the transaction's fund has no `dp_id` yet — and it isn't wrapped in a try/catch. If fund sync fails, the gift push fails too for that attempt.
</Warning>

## Recurring-Gift Linking

| WeGive Field | DonorPerfect Field | Value |
| - | - | - |
| `scheduled_donation_id` (presence) | `pledge_payment` | `"Y"` if set, `"N"` otherwise |
| `scheduledDonation.dp_id` | `plink` | The linked DonorPerfect pledge id, if the scheduled donation has already synced — otherwise `null` |

<Note>
  This only *links* a payment to an existing pledge record — it doesn't create or modify the pledge itself. See [Recurring Donation Mapping](/external/onboarding/donorperfect/data-mapping/recurring-donation) for how pledges themselves sync.
</Note>

## Tribute Information

| WeGive Field | DonorPerfect Field | Notes |
| - | - | - |
| `tribute_name` | `memory_honor` | The only tribute field mapped |

<Note>
  There is no `tribute_type` field on the WeGive `transactions` table at all (WeGive's real tribute fields are a boolean `tribute` flag plus `tribute_name`/`tribute_message`/`tribute_email`) — honor-vs.-memorial distinction isn't tracked or sent to DonorPerfect. `tribute_message` and `tribute_email` also aren't mapped.
</Note>

## Gift Narrative

| Source | Value |
| - | - |
| Fixed text | `"Online gift through WeGive"` |
| If `anonymous` | `" (Anonymous)"` appended |

<Warning>
  There is no tribute-aware narrative variant — a tribute gift's narrative is the same fixed string as any other gift; it does **not** say "In honor of \[Name]" or similar. Tribute information is carried only in the separate `memory_honor` field.
</Warning>

## Data Flow Process

1. `syncGift()` is called on transaction create/update (real-time)
2. If the owning donor has no `dp_id`, `exportDonor()` runs first (synchronously, same request)
3. If the transaction's fund has no `dp_id`, `syncFund()` runs next (synchronously, same request, not caught)
4. Under a per-transaction DB lock: if `dp_id` already exists, the previous DonorPerfect record is fetched and any locally-null param is backfilled from it before sending an update
5. If no `dp_id` yet, a reference-token lookup (`WG:txn:<id>`) runs first to recover from a possible earlier phantom-gift creation, before sending a new `dp_savegift`
6. On success, `dp_id` is stored

## Error Handling

<Warning>
  There is no automatic retry, exponential backoff, or queue management anywhere in this integration. Every `makeRequest()` call is a single unretried HTTP GET with a 120-second timeout.
</Warning>

| Symptom | Real Cause |
| - | - |
| Gift never syncs | Donor or fund sync failed first (unhandled exception propagates from `syncGift()`) |
| `Undefined id` exception | `dp_savegift` returned a 2xx with no `id`, and the reference-token recovery lookup also found nothing |
| Zero/negative amount | Not explicitly guarded in `syncGift()` — Planning Center and some other integrations skip non-positive amounts, but this specific check isn't present in `DonorPerfectIntegration.php`'s gift push path |
| Amount looks wrong | Check whether the fee was deducted as expected — `(amount - fee) / 100`, not `amount / 100` |

## API Operations

### `dp_savegift`

Full parameter list (from `syncGift()`): `gift_id`, `donor_id`, `record_type` (`"G"`), `gift_date`, `amount`, `gl_code`, `solicit_code` (always null), `sub_solicit_code` (always null), `campaign` (always null), `gift_type` (always null), `split_gift` (`"N"`), `pledge_payment`, `reference` (the `WG:txn:<id>` token), `memory_honor`, `gfname`/`glname` (always null), `fmv` (`0`), `batch_no` (`0`), `gift_narrative`, `ty_letter_no` (always null), `glink` (always null), `plink`, `nocalc` (`"N"`), `receipt` (`"N"`), `old_amount` (always null), `user_id` (`"WeGive"`), `gift_aid_date`/`gift_aid_amt`/`gift_aid_eligible_g` (always null — no Gift Aid support), `currency`, `receipt_delivery_g` (`"N"`).

<Note>
  `campaign`, `solicit_code`, `sub_solicit_code`, and `gift_type` are all always sent as `null` — there is no campaign-attribution sync of any kind in this integration, despite the dashboard exposing a "Sync Campaigns" toggle (see [Configuration Options](/external/onboarding/donorperfect/configuration-options)).
</Note>

## Data Quality Considerations

### Before Sync

* Link donors to their DonorPerfect `dp_id` before their first gift push where possible, to avoid unlinked-donor creation as a side effect
* Set up fund GL codes ahead of time if consistent GL code attribution matters (though a missing fund GL code doesn't block the gift — `gl_code` is simply sent as null/empty)

### Ongoing Maintenance

* Check Sentry (not the WeGive dashboard) for `dp_savegift` failures — there's no sync-status dashboard for this integration

## Troubleshooting

### Transactions Not Syncing

**Possible causes:**

* The integration is disabled
* The donor or fund sync (triggered inline before the gift) failed
* API authentication failure

**Solutions:**

* Confirm the integration's `enabled` flag
* Check Sentry for the specific failure — donor export, fund sync, or the gift push itself
* Verify API credentials

### Incorrect Amounts

**Possible cause:** Confirm the fee-deduction math — `(amount - fee) / 100` — matches what's expected; there's no separate currency-conversion step to account for.

### Missing Tribute Information

**Possible cause:** `tribute_name` wasn't set on the transaction, or the tribute information lives in `tribute_message`/`tribute_email`, neither of which sync to DonorPerfect at all.

**Solution:** Only `tribute_name` maps to DonorPerfect's `memory_honor` field — there's no field to carry the tribute message or the tribute-recipient's email.

## Related Documentation

<CardGroup>
  <Card title="Donor Mapping" href="/external/onboarding/donorperfect/data-mapping/donor">
    Learn how donor records are synchronized
  </Card>

  <Card title="Recurring Donations" href="/external/onboarding/donorperfect/data-mapping/recurring-donation">
    Understand recurring gift and pledge mapping
  </Card>

  <Card title="Fund Management" href="/external/onboarding/donorperfect/data-mapping/fund">
    GL code and fund designation mapping
  </Card>

  <Card title="Configuration Guide" href="/external/onboarding/donorperfect/configuration-options">
    Integration-level configuration (most sync-scope toggles are currently non-functional)
  </Card>
</CardGroup>

For additional help with transaction data mapping, contact our support team at [support@wegive.com](mailto:support@wegive.com).


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