RecurringGift Mapping
RecurringGift Mapping
WeGive Scheduled Donations map to Virtuous RecurringGift records.
Record Model
| WeGive record | Virtuous record | Correlation column |
|---|---|---|
| Scheduled Donation | RecurringGift | virtuous_id |
Frequency Mapping
| WeGive frequency | Virtuous frequency |
|---|---|
| weekly | Weekly |
| monthly | Monthly |
| quarterly | Quarterly |
| yearly | Annually |
Push (WeGive → Virtuous)
Before pushing, the integration first pushes any related records that lack a virtuous_id — the donor (Contact), the campaign (Segment), and the fund(s) (Projects).
Creating a recurring gift
POST RecurringGift{ "startDate": <start_date, Y-m-d>, "nextExpectedPaymentDate": <start_date, Y-m-d>, "frequency": "Weekly" | "Monthly" | "Quarterly" | "Annually", "amount": <charge_amount / 100>, "isPrivate": <anonymous>, "segmentId": <campaign.virtuous_id>, "designations": [ { "projectId": <project>, "amountDesignated": <dollars> } ], "contactId": <source.virtuous_contact_id>}The returned id is stored as the scheduled donation’s virtuous_id.
Amount and fees
The pushed amount is the charge_amount (base amount plus fees), not the base amount. The designations are built so their sum equals charge_amount:
- When fee-splitting is on (or no fee fund is configured), the fee is distributed proportionally across the allocation designations, with rounding absorbed by the last row.
- When a dedicated fee fund is configured, the fee is added as (or merged into) a separate designation for that fund.
This mirrors WeGive’s own recurring fee allocation so per-installment gifts and the recurring plan stay aligned in Virtuous.
Updating a recurring gift
When the scheduled donation already has a virtuous_id, the integration GETs the RecurringGift and overwrites the WeGive-owned fields, then PUTs it back:
nextExpectedPaymentDate,amount,isPrivate,segmentIddesignations— replaced entirely (WeGive is the source of truth for allocations)
Pull (Virtuous → WeGive)
RecurringGifts are pulled via POST RecurringGift/Query (1000 per page, filtered by the configured pull_by date) and imported as Scheduled Donations, matched on virtuous_id:
| WeGive field | Source | Notes |
|---|---|---|
virtuous_id | recurring gift id | |
start_date | nextExpectedPaymentDate | |
created_at | createDateTimeUtc | |
deleted_at | cancelDateTimeUtc | Set when the gift is cancelled in Virtuous |
frequency | reverse of the frequency map above | |
anonymous | isPrivate | |
amount | amount * 100 | New records only |
fee_amount | 0 | New records only |
amountandfee_amountare set only on first import. On existing records, WeGive is the source of truth — Virtuous stores the fee-inflatedcharge_amount, so pulling it would create a feedback loop of growing fees.
Source resolution: a company donor (by virtuous_contact_id, no individual) is tried first; otherwise the Contact’s primary individual. Fund comes from the first designation’s projectId; campaign from segmentId. When fund allocations are enabled, allocations are synced to WeGive from the designations on first import only (amountDesignated * 100 → allocation amount).
This reflects the integration as implemented in app/Integrations/Virtuous.php.