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

# Virtuous Data Mapping Overview

> How WeGive objects map to Virtuous CRM objects, and how the integration pushes and pulls each one

# Data Mapping Overview

This document describes how the WeGive donor platform maps to Virtuous CRM objects and how each object is synchronized in both directions. The mappings here reflect the actual behavior of the integration, including the specific Virtuous API endpoints, fields, and transformations used.

## Object Mapping Summary

| WeGive Object | Virtuous Object | Push (WeGive → Virtuous) | Pull (Virtuous → WeGive) |
| - | - | - | - |
| Donor (individual) | `ContactIndividual` (within a `Contact`) | Create/update | Create/update |
| Donor (company) / Household | `Contact` (`Organization` / `Household`) | Create/update | Create/update |
| Transaction | `Gift` | Create/update (batch or real-time) | Create/update |
| Fund | `Project` | Create only | Create/update |
| Campaign | `Segment` | Create/update | Create/update |
| Scheduled Donation | `RecurringGift` | Create/update | Create/update |

<Warning>
  Virtuous's "Giving Overview" computed/reporting fields — Rolling Year Giving, Life To Date (+Passthrough) Gift Count, Segment Code, Contact Type, Gift Type, Largest/Last Gift Amount Overall, First/Last Gift Date Overall, Life To Date Gift Count — are **not supported**. These are fields Virtuous computes on top of its own Gift/Contact records; WeGive's integration only ever pulls the underlying real Gift/Contact/Project/Segment/RecurringGift records (see the mapping tables below), never Virtuous's own derived reporting fields. WeGive computes its own, narrower set of giving aggregates directly on the donor record instead — a lifetime total and a fixed calendar-year total. There is no equivalent for an arbitrary rolling 12-month window, a passthrough-adjusted lifetime total, or Virtuous's Segment Code/Contact Type/Gift Type fields — if you need one of these for an audience rule, you'll need to approximate it using WeGive's standard date-range and transaction-amount filters instead.
</Warning>

Detailed field-level mappings live on the per-object pages:

* [Contact Mapping](./contact)
* [Gift Mapping](./gift)
* [Project Mapping](./project)
* [Segment Mapping](./segment)
* [RecurringGift Mapping](./recurring-gift)

## Correlation Fields

WeGive tracks the corresponding Virtuous record using these columns:

| WeGive Record | Column(s) | References |
| - | - | - |
| Donor (individual) | `virtuous_contact_id` | The parent Virtuous `Contact` |
| Donor (individual) | `virtuous_contact_individual_id` | The Virtuous `ContactIndividual` |
| Donor (individual) | `virtuous_is_primary_contact_individual` | Whether this donor is the Contact's primary individual |
| Donor (company) | `virtuous_contact_id` | The Virtuous `Contact` (no individual) |
| Household | `virtuous_id` | The Virtuous `Contact` |
| Transaction | `virtuous_id` | The Virtuous `Gift` ID, or a synthetic batch ID prefixed `btch_` |
| Fund | `virtuous_id` | The Virtuous `Project` |
| Campaign | `virtuous_id` | The Virtuous `Segment` |
| Scheduled Donation | `virtuous_id` | The Virtuous `RecurringGift` |

Transactions sent through the batch importer are marked with a synthetic ID like `btch_WeGive_Import` rather than a real Gift ID. The integration treats `btch_*` values as "synced but not individually addressable" and will not attempt to update those gifts.

## Sync Directions

<Warning>
  There's no dashboard setting that turns push or pull on/off per object type — every object type listed above pushes and pulls unconditionally once the integration is enabled. See [Configuration Options](/external/onboarding/virtuous/configuration-options) for the full picture.
</Warning>

* **Funds are create-only on push** — once a Fund has a `virtuous_id`, the integration does not update the Virtuous `Project`.

### Push triggers

* **Real-time:** When `real_time` is enabled, individual transactions are pushed as they occur, and a Virtuous webhook (`contactUpdate`) notifies WeGive of contact changes. Real-time transaction push is skipped entirely when `real_time` is disabled.
* **Batch:** Transactions are sent in batches (default 100 per request) to `v2/Gift/Transactions`. This is the default path for bulk processing.

### Related-entity push

Pushing a transaction or scheduled donation will first push any related records that don't yet have a `virtuous_id` — the owner/donor, the campaign, and the fund(s) — so the gift can reference real Virtuous IDs.

## Matching Logic

When importing from Virtuous, records are matched in this order:

**Contacts / Donors**

1. `virtuous_contact_individual_id` on the donor
2. `virtuous_contact_id` + primary-individual flag (or the company donor for `Organization`-type contacts)
3. Create new

**Transactions**

1. `virtuous_id` (the Gift ID)
2. The `wg_id` custom field that WeGive wrote on the gift (links back to the original WeGive transaction)
3. Create new

**Funds / Campaigns / Scheduled Donations**

* Matched on `virtuous_id`.

## Virtuous API Endpoints Used

All requests use base URL `https://api.virtuoussoftware.com/api/` with a Bearer API key. Write requests append `?disableWebhookUpdates=true` so WeGive's own writes don't trigger echo webhooks.

### Pull (query) endpoints

Pulls page through Virtuous's query endpoints (1000 records per page), filtered by the configured `pull_by` date field using `OnOrAfter` / `OnOrBefore`:

* `POST Contact/Query/FullContact`
* `POST ContactIndividual/Query`
* `POST Gift/Query/FullGift`
* `POST Project/Query`
* `POST Segment/Query`
* `POST RecurringGift/Query`

### Push endpoints

* `POST Contact`, `PUT ContactIndividual/{id}`, `POST/PUT ContactMethod`, `POST/PUT ContactAddress`
* `POST Gift`, `PUT Gift/{id}` (real-time, single gift)
* `POST v2/Gift/Transactions` (batch gift import)
* `POST Project`
* `POST Segment`, `PUT Segment/{id}`
* `POST RecurringGift`, `PUT RecurringGift/{id}`
* `POST Webhook` (registers the `contactUpdate` webhook when the integration is enabled)

### Reliability

* **Rate limiting:** On HTTP 429, requests retry up to 3 times, sleeping until the `X-RateLimit-Reset` time (capped at 240 seconds).
* **Timeouts:** Requests use a 300-second timeout.

## Amount Handling

WeGive stores monetary amounts in **cents**; Virtuous uses **dollars**. All amounts are divided by 100 on push and multiplied by 100 on pull.

## Notes

* Donors with no first or last name are pushed with the sentinel values `FNU` (First Name Unknown) / `LNU` (Last Name Unknown), which Virtuous requires. These sentinels are stripped back to `null` when WeGive creates user logins on pull.
* The integration never deletes Virtuous contact methods that exist in Virtuous but not in WeGive, to preserve data entered directly in Virtuous.

This overview reflects the integration as implemented. See the per-object pages for exact field mappings.


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