How custom fields work
Each resource type has its own independent custom field configuration. A nonprofit can have ten custom fields on Contacts, three on Gifts, and zero on Projects — every resource is configured separately. The configuration is per-organization, not platform-wide: every nonprofit customer of yours may have a different set of custom fields enabled. This has one critical implication for partners:Resources that support custom fields
| Resource | Discovery endpoint |
|---|---|
| Contact | GET /api/Contact/CustomFields |
| ContactIndividual | GET /api/ContactIndividual/CustomFields |
| ContactNote | GET /api/ContactNote/CustomFields |
| Gift | GET /api/Gift/CustomFields |
| GiftAsk | GET /api/GiftAsk/CustomFields |
| RecurringGift | GET /api/RecurringGift/CustomFields |
| Project | GET /api/Project/CustomFields |
| Pledge | GET /api/v2/Pledge/CustomFields |
| PlannedGift | GET /api/PlannedGift/CustomFields |
| Premium | GET /api/Premium/CustomFields |
| Event | GET /api/Event/CustomFields |
| EventAttendee | GET /api/EventAttendee/CustomFields |
| Grant | GET /api/Grant/CustomFields |
| VolunteerOpportunity | GET /api/VolunteerOpportunity/CustomFields |
Discovering available fields
GET /api/Contact/CustomFields (and its siblings) returns an array describing every custom field configured on the resource:
| Field | Description |
|---|---|
name | The internal field name. Use this in customFields[].name when reading or writing values on a record. |
displayName | The label shown in the Virtuous UI. Use this when presenting the field to your customer for mapping. |
dataType | The data type — drives how to serialize the value when writing. See Data types below. |
options | For Dropdown (and similar enum-style) fields, the list of valid values. Empty array for free-form fields. |
Data types
The CRM+ spec types every custom field value asstring — both on read and on write. The live API accepts and returns the natural representation for each dataType, but partner integrations need to know which serialization to use when sending values.
dataType | What it stores | Wire format on write |
|---|---|---|
Text | Free-text strings | String, e.g., "Major Donor". |
Number | Numeric values | String containing the number, e.g., "850" (the spec types it as string; the value is treated as numeric internally). |
Date | Calendar dates | ISO 8601 date string, e.g., "2024-12-15". |
Boolean | True/false flags | The string "true" or "false". |
Dropdown | One value from a fixed set | One of the strings listed in the field’s options array. The value must match exactly — "Email" is valid; "email" may be rejected. |
Reading custom field values
Custom field values appear on the resource record as acustomFields array. Each entry references the field by name and carries its current value:
customFields array or present with an empty value. Always default safely on missing values.
Writing custom field values
When creating or updating a record, include thecustomFields array with the fields you want to set. Only the fields you include are written — fields you omit are unchanged (consistent with the PUT-as-PATCH behavior covered on the Contacts page).
cURL
- The
namefield must match the configured field name exactly. Use the values from the discovery endpoint, not the display names."wealthScore"is correct;"Wealth Score"is not. - Dropdown values must match one of the configured options exactly (case-sensitive). The discovery endpoint returns the valid options for each Dropdown field — your integration should validate against that list before submitting.
- Sending an empty
valueclears the field. If you want to remove a value, send{ "name": "fieldName", "value": "" }. Omitting the field entirely from thecustomFieldsarray leaves it unchanged.
Custom Collections — the multi-instance variant
Some data doesn’t fit a single-value custom field — for example, “multiple board memberships, each with start date and role.” For these cases CRM+ supports Custom Collections, which are configurable multi-instance sub-records on a Contact or ContactIndividual. A Custom Collection has:- A name (e.g., “Board Memberships”).
- A set of fields (each with a name, displayName, dataType, and optional options).
- Multiple collection instances per record — each instance is one row of data in the collection.
Discovering Custom Collections
| Endpoint | Use |
|---|---|
GET /api/Contact/CustomCollections | List Custom Collections configured on Contacts. |
GET /api/ContactIndividual/CustomCollections | List Custom Collections configured on ContactIndividuals. |
id, name, and fields array. The fields array has the same shape as standard custom fields — each field has a name, displayName, dataType, and options.
Reading Custom Collection values
Custom Collection instances appear on the record as acustomCollections array, with each entry containing the collection’s metadata and a fields array of name/value pairs for that instance:
Writing Custom Collection instances
POST /api/Contact/{contactId}/Collection/{customCollectionId} creates a new instance on a Contact. The request body provides the field values for the new instance. Other endpoints update or delete individual instances by collectionInstanceId.
Custom Collections are a more advanced feature than standard Custom Fields and are used by a smaller subset of nonprofits. Most partner integrations only need to read and write standard Custom Fields. If your customer has a use case that requires multi-instance data on a single record, Custom Collections are the right tool — but reach out to your Virtuous partner contact for setup guidance, because the configuration is typically managed in close coordination with the nonprofit’s Virtuous administrator.
Partner integration patterns
Pattern 1: Custom fields as a partner-side write target
Use custom fields to write partner-specific data into Virtuous records — for example, a Stripe customer ID, a Mailchimp subscription status, an engagement score from your platform. The discovery endpoint lets your customer’s Virtuous administrator configure the fields once, and your integration reads/writes them by name. This is the cleanest pattern for storing your platform’s metadata on Virtuous records without polluting the standard schema.Pattern 2: Custom fields as a partner-side read source
Some partner integrations need to read custom field values that the nonprofit maintains in Virtuous — for example, a marketing automation tool that uses a “wealthScore” custom field to segment outreach. Use the discovery endpoint plus the Contact read endpoints, and surface a mapping UI to your customer so they can point your integration at the right custom fields.Pattern 3: Custom fields as a configuration channel
For more advanced integrations, custom fields can carry per-record configuration that affects how your integration treats the record — for example, aexcludeFromAutomation Boolean field that suppresses your platform’s actions for that donor. This pattern requires careful customer onboarding (the nonprofit must configure the field and populate it), but it offers a customer-controllable extension point without requiring code changes in your integration.
Where to go next
Contacts
The Contact resource — the most common target for custom field reads and writes.
Donations / Gifts
Gifts have their own custom field schema — separate from Contacts.
Relationships and IDs
The complementary pattern — using
contactReferences for cross-system identifiers.Statuses and Lifecycle States
Boolean custom fields are often used as ad-hoc lifecycle flags.