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

# Recurring Gifts

> The RecurringGift resource in Raise — the schedule that produces Gifts over time, the payment processing model, and the lifecycle from creation through cancellation.

A RecurringGift in Raise is a schedule — a commitment by a donor to give a specified amount at a regular interval. Each time the schedule runs, the payment processor charges the donor's stored payment method and creates a new Gift record linked to the schedule via `recurringGiftId`.

This page covers the RecurringGift resource shape, the relationship between the schedule and the Gifts it produces, the lifecycle states the schedule moves through, and the operations partner integrations use most: updates, cancellations, and activity inspection.

## The RecurringGift record

The RecurringGift record is one of the richest in the Raise API — over 50 fields covering identity, schedule, payment method, status, and processing history.

### Schedule and amount

| Field                     | Type         | Description                                                                  |
| ------------------------- | ------------ | ---------------------------------------------------------------------------- |
| `id`                      | integer      | The Raise primary key for this schedule. Immutable.                          |
| `amount`                  | number       | The per-payment amount.                                                      |
| `currencyCode`            | string       | The currency for the schedule.                                               |
| `formattedAmount`         | string       | The per-payment amount pre-formatted for display.                            |
| `frequency`               | integer enum | How often the schedule runs (monthly, quarterly, yearly, etc.).              |
| `formattedFrequency`      | string       | The frequency display string.                                                |
| `startDate`               | string       | When the schedule began.                                                     |
| `startDateFormatted`      | string       | Formatted start date for display.                                            |
| `nextChargeDate`          | string       | The next scheduled charge date.                                              |
| `nextChargeDateFormatted` | string       | Pre-formatted next charge date.                                              |
| `successfulCycles`        | integer      | The count of successfully-processed payments so far.                         |
| `total`                   | number       | The total committed amount for a finite-duration schedule (when applicable). |
| `formattedTotal`          | string       | Formatted total amount.                                                      |

<Note>
  `frequency` is an integer enum (the spec shows the type as a `$ref` to a `Frequency` enum without documented label-to-integer mappings). Use `formattedFrequency` for display. For programmatic logic, discover the integer-to-label mapping through the live API or coordinate with the platform team before relying on specific integer values.

  **⚠️ Spec gap:** RecurringGift `frequency` enum values are not documented in the spec. Same applies to `status` (see below). Future spec updates are expected to label these.
</Note>

### Status and processing health

| Field              | Type         | Description                                            |
| ------------------ | ------------ | ------------------------------------------------------ |
| `status`           | integer enum | Current lifecycle status (active, cancelled, etc.).    |
| `statusText`       | string       | Display string for the status.                         |
| `hasPaymentFailed` | boolean      | `true` if the most recent payment attempt failed.      |
| `isLegacy`         | boolean      | `true` if the schedule was created in a legacy system. |
| `isAnonymous`      | boolean      | `true` if the donor chose to remain anonymous.         |
| `isTestMode`       | boolean      | `true` for schedules in test mode.                     |

The `hasPaymentFailed` flag is one of the most important fields for stewardship integrations. When `true`, the schedule has not been able to charge the donor's payment method — typically because the card expired, was reissued, or had insufficient funds. The customer's team needs to reach out to the donor to update payment info before the schedule can resume.

### Donor and linkage

| Field            | Type       | Description                                                  |
| ---------------- | ---------- | ------------------------------------------------------------ |
| `donor`          | DonorModel | Embedded donor data.                                         |
| `crmKey`         | string     | The schedule's primary key in the external CRM (e.g., CRM+). |
| `crmKeyUrls`     | object     | CRM URLs by integration type.                                |
| `organizationId` | integer    | The Raise organization ID.                                   |
| `profileNumber`  | string     | A donor-facing identifier for the schedule.                  |

### Designation

| Field                                                         | Type                                         | Description                                                                                              |
| ------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `projectAllocation`                                           | array of RecurringGiftProjectAllocationModel | The breakdown of each recurring payment across Projects. Same model as a Gift's `projects[]` allocation. |
| `premium`                                                     | object                                       | The Premium associated with the schedule (one-time premium given at signup).                             |
| `recurringPremium`                                            | object                                       | A Premium given on each recurring payment (when applicable).                                             |
| `tribute`                                                     | object                                       | Tribute or memorial information.                                                                         |
| `motivationCode`, `motivationCodeId`, `motivationCodeGroupId` | various                                      | Attribution codes.                                                                                       |
| `segmentId`, `segmentName`, `segmentCode`                     | various                                      | Segment attribution.                                                                                     |
| `sourceCode`                                                  | string                                       | Source code attribution.                                                                                 |

### Payment method

| Field                      | Type    | Description                                                                  |
| -------------------------- | ------- | ---------------------------------------------------------------------------- |
| `paymentMethodId`          | string  | The tokenized payment method.                                                |
| `paymentInfo`              | string  | Display string summarizing the payment method (e.g., "Visa ending in 4242"). |
| `cardBrand`                | string  | The credit card brand, when applicable.                                      |
| `expMonthAndYear`          | string  | The card's expiration.                                                       |
| `paymentMethodCountryCode` | string  | The country code of the payment method.                                      |
| `paymentProviderType`      | enum    | The payment provider type.                                                   |
| `paymentTenderType`        | enum    | The payment tender type.                                                     |
| `gatewayId`                | integer | The payment gateway.                                                         |
| `gateway`                  | string  | The gateway display name.                                                    |
| `gatewayCustomerKey`       | string  | The gateway's identifier for the customer.                                   |
| `merchantType`             | enum    | The merchant type.                                                           |
| `merchantAccount`          | string  | The merchant account identifier.                                             |
| `tokenizationKey`          | string  | The tokenization key.                                                        |

The payment method fields enable partner integrations to detect upcoming expirations (using `expMonthAndYear`) and proactively contact donors to update their cards before the schedule fails.

### Costs and currency

| Field              | Type    | Description                                                  |
| ------------------ | ------- | ------------------------------------------------------------ |
| `donorCoverCosts`  | boolean | `true` if the donor opted to cover processing fees.          |
| `costs`            | number  | The processing fee amount the donor is covering.             |
| `baseCurrencyCode` | string  | The base currency code (when different from `currencyCode`). |
| `currencyExchange` | object  | Currency exchange information.                               |

### Audit and other

| Field          | Type   | Description                                         |
| -------------- | ------ | --------------------------------------------------- |
| `createdDate`  | string | When the schedule was created.                      |
| `modifiedDate` | string | When the schedule was last changed.                 |
| `notes`        | string | Internal notes.                                     |
| `comments`     | string | Donor-provided comment.                             |
| `page`         | object | The donation page the schedule was created through. |

***

## How RecurringGifts produce Gifts

The RecurringGift schedule is the durable schedule record. The actual Gifts the schedule produces are separate records — see [Gifts](/raise/concepts/gifts).

The data flow on each payment cycle:

```mermaid theme={null}
sequenceDiagram
  participant Schedule as RecurringGift Schedule
  participant Processor as Raise Payment Processor
  participant Gift as Gift Record
  participant Webhook as Webhook Subscribers

  Note over Schedule: nextChargeDate reached
  Schedule->>Processor: Charge stored paymentMethodId
  alt Charge succeeds
    Processor->>Gift: Create Gift with recurringGiftId = schedule.id
    Schedule->>Schedule: Increment successfulCycles<br/>Set new nextChargeDate
    Gift->>Webhook: Fire giftCreate event
  else Charge fails
    Schedule->>Schedule: Set hasPaymentFailed = true<br/>(no Gift created)
  end
```

Two patterns this implies for partner integrations:

* **Each recurring payment is a separate Gift.** Subscribing to `giftCreate` webhooks captures recurring payments alongside one-time donations. Distinguish them by checking `gift.recurringGiftId` — if non-null, the gift came from a schedule.
* **Schedule state changes are visible on the RecurringGift record, not via dedicated events.** When a schedule's `nextChargeDate` advances or `successfulCycles` increments, the RecurringGift record changes — partner integrations that need to track schedule state pull the record on a cadence rather than rely on an event.

***

## Reading RecurringGifts

| Pattern         | Endpoint                        | Use                                                                                                  |
| --------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------- |
| List all        | `GET /api/RecurringGift/list`   | Paginated list of all schedules                                                                      |
| Query by filter | `POST /api/RecurringGift/query` | Advanced filtering — see [Pagination and Filtering](/raise/pagination#pagination-on-query-endpoints) |
| Get by ID       | `GET /api/RecurringGift/{id}`   | Single schedule with full detail                                                                     |

For partner integrations that need a specific donor's schedules, use the donor-scoped endpoint:

```bash cURL theme={null}
curl https://prod-api.raisedonors.com/api/Donor/12345/recurringgifts \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

This is cheaper than a full Query with a `donorId` filter.

### Reading the activity (payment) history

```bash cURL theme={null}
curl https://prod-api.raisedonors.com/api/RecurringGift/9876/activities \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

Returns the payment history for the schedule — successful charges, failed attempts, and any other lifecycle events. Use this to build donor-facing payment history views or to investigate schedules with payment issues.

***

## Creating RecurringGifts

The Raise API doesn't expose a dedicated `POST /api/RecurringGift` create endpoint. RecurringGifts are created in one of two ways:

| Source                                                  | Path                                                                |
| ------------------------------------------------------- | ------------------------------------------------------------------- |
| **Donor opts into recurring giving on a donation form** | `POST /api/Raise/give` with `isRecurring: true` and `frequency` set |
| **Manual entry**                                        | Through the Raise admin UI                                          |

For partner integrations enabling recurring donations through a custom flow, the path is `POST /api/Raise/give` with the recurring fields set:

```bash cURL theme={null}
curl -X POST https://prod-api.raisedonors.com/api/Raise/give \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 50.00,
    "paymentMethodId": "tok_abc123",
    "paymentMethodType": "CreditCard",
    "isRecurring": true,
    "frequency": 1,
    "startDate": "2025-02-01",
    "donor": {
      "firstName": "Bruce",
      "lastName": "Wayne",
      "email": "bruce@wayne.example"
    }
  }'
```

This creates the RecurringGift schedule **and** processes the first payment, producing both a RecurringGift record and the first Gift. The schedule's `nextChargeDate` advances to the next interval after the first payment.

<Note>
  The `frequency` integer value needed for the request is not documented in the spec. Confirm the integer-to-frequency mapping (monthly = 1, quarterly = 2, etc.) before relying on it in production.
</Note>

***

## Updating a RecurringGift

`PUT /api/RecurringGift/{id}` updates an existing schedule. Common updates partner integrations make:

| Change                                | Fields to update                                           |
| ------------------------------------- | ---------------------------------------------------------- |
| Donor changes the recurring amount    | `amount`, `projectAllocation` (must sum to the new amount) |
| Donor changes the frequency           | `frequency`, `nextChargeDate`                              |
| Donor updates payment method          | `paymentMethodId` (plus card-specific fields)              |
| Donor changes the designation         | `projectAllocation`                                        |
| Customer's team adds an internal note | `notes`                                                    |

The Raise spec doesn't expose a PATCH variant for RecurringGift, so partial updates use the GET-then-PUT pattern:

```javascript JavaScript theme={null}
async function changeRecurringAmount(recurringGiftId, newAmount, newProjectAllocation) {
  // 1. Read the current state
  const current = await fetch(
    `https://prod-api.raisedonors.com/api/RecurringGift/${recurringGiftId}`,
    { headers: { Authorization: `Bearer ${process.env.RAISE_API_TOKEN}` } }
  ).then((r) => r.json());

  // 2. Apply the changes
  const updated = {
    ...current,
    amount: newAmount,
    projectAllocation: newProjectAllocation,
  };

  // 3. Write back
  const response = await fetch(
    `https://prod-api.raisedonors.com/api/RecurringGift/${recurringGiftId}`,
    {
      method: 'PUT',
      headers: {
        Authorization: `Bearer ${process.env.RAISE_API_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(updated),
    }
  );
  return response.json();
}
```

The next charge cycle will use the updated values.

<Warning>
  When changing `amount`, the `projectAllocation` entries must sum to the new amount. The API rejects schedule updates where the allocation total doesn't match. Update both together in a single PUT.
</Warning>

***

## Cancelling a RecurringGift

Cancellation has a dedicated endpoint — don't try to cancel by setting `status` directly via PUT:

```bash cURL theme={null}
curl -X PUT https://prod-api.raisedonors.com/api/RecurringGift/9876/cancel \
  -H "Authorization: Bearer YOUR_API_TOKEN"
```

The endpoint transitions the schedule to its cancelled state and prevents future charge cycles. Any already-processed Gifts produced by the schedule remain attached to it for historical reference.

After cancellation, the schedule's `nextChargeDate` no longer triggers payment processing. Whether the schedule can be reactivated depends on the platform's lifecycle rules — confirm with the platform team before designing any "resume cancelled schedule" workflow.

***

## Detecting payment failures

Schedules with `hasPaymentFailed: true` are the most actionable signal for stewardship integrations. Query for them on a regular cadence:

```javascript JavaScript theme={null}
async function findFailedSchedules() {
  const response = await fetch(
    'https://prod-api.raisedonors.com/api/RecurringGift/query',
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${process.env.RAISE_API_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        skip: 0,
        take: 1000,
        groups: [
          {
            conditions: [
              // Discover the right parameter name and operator via QueryOptions
              { parameter: 'hasPaymentFailed', operator: 0 /* equals */, value: 'true' },
            ],
          },
        ],
      }),
    }
  );
  return (await response.json()).items;
}
```

When schedules are detected with failures, the customer's team can be alerted to reach out to the donor with a payment-update link. The personalized-page generation endpoint (`POST /api/Donor/{donorId}/generate-page` — see [Donation Forms](/raise/concepts/donation-forms#2-personalized-page-generation-for-a-donor)) is the typical mechanism for delivering an update-payment URL.

***

## Detecting upcoming card expirations

Another high-value stewardship signal: schedules with payment methods that will expire soon. The `expMonthAndYear` field on each RecurringGift indicates the card expiration.

```javascript JavaScript theme={null}
async function findSchedulesExpiringSoon(monthsAhead = 2) {
  const allSchedules = await listAllRecurringGifts(); // paginated read
  const now = new Date();
  const cutoff = new Date(now.getFullYear(), now.getMonth() + monthsAhead, 1);

  return allSchedules.filter((s) => {
    if (!s.expMonthAndYear) return false;
    // Parse "MM/YYYY" or similar — confirm format against live API
    const [month, year] = s.expMonthAndYear.split('/').map(Number);
    const expDate = new Date(year, month - 1, 1);
    return expDate < cutoff;
  });
}
```

<Note>
  The exact format of `expMonthAndYear` (e.g., `MM/YYYY`, `MM/YY`, or another shape) is not documented in the spec. Confirm the format against live data before parsing.
</Note>

Schedules with upcoming expirations are prime targets for proactive donor outreach — much higher success rate than waiting for the payment to fail.

***

## Where to go next

<CardGroup cols={2}>
  <Card title="Gifts" icon="hand-holding-dollar" href="/raise/concepts/gifts">
    The Gift records that recurring schedules produce on each cycle.
  </Card>

  <Card title="Configure a Recurring Gift" icon="arrows-rotate" href="/raise/workflows/configure-a-recurring-gift">
    The workflow for setting up a recurring schedule.
  </Card>

  <Card title="Donors" icon="user" href="/raise/concepts/donors">
    The donor records that schedules belong to, including the transfer-recurring-gift operation.
  </Card>

  <Card title="Statuses and Lifecycle States" icon="circle-half-stroke" href="/raise/concepts/statuses-and-lifecycle-states">
    The full lifecycle catalog including RecurringGift status values.
  </Card>
</CardGroup>
