Skip to main content
A recurring donor is a donor who has committed to giving on a schedule — 50/monthtogeneralfund,50/month to general fund, 25/week to a campaign, $1,200/year as an annual pledge. In Virtuous, this commitment is represented as a RecurringGift record, separate from but linked to the actual Gift records that get created each time the schedule produces a payment. This recipe covers the full RecurringGift lifecycle from the partner integration perspective: creating a schedule when a donor signs up, updating it when they change their amount or designation, cancelling it when they end the commitment, and linking each scheduled payment back to the schedule. The Virtuous-side endpoints are all API-accessible, so unlike Contact merges, the entire lifecycle can be managed programmatically. If your integration only handles one-time gifts, you can skip this page. Anything that handles recurring donations needs the patterns here.

The data model

The RecurringGift describes the schedule (frequency, amount, designations, start date, status). Each scheduled payment becomes its own Gift record, linked to the RecurringGift via the recurringGiftTransactionId field on the Gift Transaction submission. Two important consequences of this model:
  • The RecurringGift itself is not money. It’s a commitment record. The Gifts that get linked to it represent actual transactions.
  • Cancelling a RecurringGift does not delete past Gifts. Cancellation stops new payments from being recorded against the schedule; the historical record of past payments remains.

RecurringGift endpoints

The endpoints available for managing RecurringGifts:

Creating a schedule

When a donor signs up for a recurring donation on your platform — a Stripe Subscription, a recurring scheduled donation in your platform’s database — create the corresponding RecurringGift in Virtuous.
The response contains the new schedule’s id — store it on your side alongside your platform’s commitment record.

Frequency values

The CRM+ spec does not enumerate the valid frequency values for RecurringGifts. Common patterns include Monthly, Quarterly, Annually, and Weekly — but the canonical enum is not documented.

Pre-flight: the donor’s Contact must exist

POST /api/RecurringGift takes a contactId directly — there is no embedded contact data with matching, unlike POST /api/v2/Gift/Transaction. Resolve or create the donor’s Contact before creating the schedule:
JavaScript
This sequencing makes RecurringGift creation slower than Gift Transaction creation — you have to wait for the Contact to resolve through the nightly batch before the schedule can be created. For new donors signing up for recurring giving, this means the RecurringGift typically isn’t created in Virtuous until the day after the donor signed up. If your platform’s flow needs the schedule visible in Virtuous faster, the alternative is to submit the first payment via POST /api/v2/Gift/Transaction (which has embedded contact matching) and create the RecurringGift after the Contact appears. The RecurringGift links forward to the next payment; the first payment is one-off in Virtuous.

Linking payments to a schedule

Each time the recurring schedule produces a payment — Stripe charges the subscription, your platform’s recurring billing fires — submit a Gift Transaction with recurringGiftTransactionId set to the schedule’s transactionId:
JavaScript
Two pieces:
  • transactionId is the specific payment’s ID — different on every payment of the schedule.
  • recurringGiftTransactionId is the schedule’s ID — the same value on every payment.
Virtuous’s matching algorithm uses recurringGiftTransactionId to associate the new Gift with the existing schedule. In the UI, the Gift appears in the schedule’s payment history; in reports, the donor’s recurring total reflects the new payment.

Updating a schedule

When the donor changes their recurring amount, switches their designation, or otherwise modifies the schedule, push the change to Virtuous with PUT /api/RecurringGift/{recurringGiftId}. Follow the same GET-then-PUT pattern as Contact updates (see Update a Contact):
JavaScript
The same PUT-as-PATCH ambiguity discussed in Update a Contact applies — send the complete record on every update.

Common update scenarios


Cancelling a schedule

When a donor ends their recurring commitment — actively unsubscribes, cancels in your platform’s portal, or has their payment method fail past the dunning threshold — cancel the schedule in Virtuous:
cURL
JavaScript
The dedicated Cancel endpoint is the right path for cancellation. Do not use PUT /api/RecurringGift/{id} with status: "Cancelled" — the canonical lifecycle transition is via the Cancel endpoint, which sets the cancelDateTimeUtc field and triggers the appropriate audit log entry.
The CRM+ API does not document an explicit endpoint to pause-and-resume a recurring schedule. Cancellation is one-way. If your platform supports pause/resume and you need to model that in Virtuous, two options:
  1. Cancel the existing schedule and create a new one when the donor resumes.
  2. Maintain pause/resume state on your side and stop submitting payment Gift Transactions during the paused period — the Virtuous schedule appears active but receives no payments.
Option 2 is generally less disruptive to reporting but produces a schedule with no payments during the pause window — which may confuse the customer’s team. Discuss with the customer.

Handling failed payments

When a scheduled payment fails (card expired, insufficient funds, account closed), the partner platform typically enters a dunning state — retrying the payment over several days before giving up. The Virtuous-side handling depends on the eventual outcome: Importantly: do not submit failed payments as Gifts to Virtuous. A failed payment is not a gift, and recording it produces incorrect totals. Only submit when the payment actually succeeded. If the customer’s team needs visibility into failed payments — for outreach to the donor — surface them in your integration’s UI or as a separate report, not as Virtuous Gifts.

Reconciliation

Periodic reconciliation between your platform’s recurring schedules and Virtuous catches drift:
JavaScript
Run reconciliation monthly. Mismatches typically surface a donor who changed their amount through your platform but the change didn’t propagate to Virtuous — re-push the update to resolve.

End-to-end checklist

Before deploying a recurring-donation integration to production, confirm:
  • RecurringGifts are created with stable transactionSource + transactionId (the schedule’s ID, not a payment’s ID).
  • The donor’s Contact is resolved before RecurringGift creation.
  • Each recurring payment Gift Transaction includes recurringGiftTransactionId linking back to the schedule.
  • Schedule updates use GET-then-PUT with the full record.
  • Cancellations use PUT /api/RecurringGift/Cancel/{id}, not status updates via standard PUT.
  • Failed payments are not submitted as Gifts.
  • Monthly reconciliation runs and surfaces amount/status drift between your platform and Virtuous.
  • If your platform supports pause/resume, the chosen Virtuous-side modeling (cancel/recreate vs. suppress-payments) is documented and agreed with the customer.

Where to go next

Stripe to Virtuous CRM

The Stripe-specific recipe that sources recurring schedules from Stripe Subscriptions.

Import Historical Gifts

Backfill historical recurring payment data — each payment as a Gift, linked to the recreated schedule.

Statuses and Lifecycle States

The RecurringGift status field and its lifecycle states.

Reconcile Failed Syncs

Handle drift in recurring schedule state between your platform and Virtuous.
Last modified on May 27, 2026