- IDs — how records are uniquely identified, both internally to Virtuous and via external references that bridge your platform’s identifiers with Virtuous’s.
- Relationships — the explicit resource that models connections between Contacts (spouses, parents, employers, etc.).
Part 1: Identifier patterns
Primary keys
Every resource in CRM+ has a numericid field as its primary key. IDs are assigned at creation time, are unique within an organization, and are immutable.
| Resource | Primary key field |
|---|---|
| Contact | id |
| ContactIndividual | id |
| ContactAddress | id |
| Gift | id |
| GiftDesignation | id |
| Project | id |
| Campaign | campaignId |
| Segment | id |
| RecurringGift | id |
| Pledge | id |
| Relationship | id |
Campaign is the one resource whose primary key is named after the resource (
campaignId) rather than the standard id. Every other resource uses plain id on its own record and {resource}Id only when referenced from elsewhere. The campaignId naming on Campaign itself is a spec quirk; treat it as the Campaign’s primary key.Foreign keys
When one resource references another, the field name follows the pattern{resource}Id. A Gift references its Contact through contactId; a GiftDesignation references its Project through projectId.
Id (other than id itself), it is a foreign key to another resource.
ID scoping — IDs are per-organization
A CRM+ ID is unique within a single Virtuous organization, but not unique across organizations. A Contact withid: 4821 in one nonprofit’s instance is unrelated to a Contact with id: 4821 in another nonprofit’s instance. The numerical space is independent per organization.
The simplest pattern: every record in your partner integration’s database that references a Virtuous record stores three columns — your customer identifier, the Virtuous resource type, and the Virtuous ID.
External reference identifiers
Two patterns let your platform’s identifiers travel alongside Virtuous IDs, eliminating the need to store the Virtuous ID separately for the most common workflows.Contact references — contactReferences[]
Contacts carry an array of external reference identifiers:
source (your platform name) with an id (your platform’s identifier for the same donor). A Contact can have many references — one per integrated system.
Setting references on Contact creation. Include referenceSource and referenceId in the Contact body or in the embedded contact block of a Gift Transaction. The Transaction endpoint uses these as the highest-priority match signal, so duplicate-prevention is most reliable when you set them.
Looking up a Contact by reference. Two endpoints support this:
| Endpoint | Auth | Use |
|---|---|---|
GET /api/Contact/{referenceSource}/{referenceId} | Standard Bearer | The recommended path — both parts in the URL path. |
GET /api/Contact/ByReference/{referenceId} | HMAC only | Older single-segment path. Requires HMAC authentication — contact Virtuous support for HMAC credentials. |
cURL
Gift references — transactionSource + transactionId
Gifts use a single source/id pair (not an array — gifts have at most one external reference):
- Idempotency. When you re-submit a Gift Transaction with the same
(transactionSource, transactionId)pair, Virtuous recognizes it as a duplicate and does not create a second Gift. - Lookup.
GET /api/Gift/{transactionSource}/{transactionId}retrieves the Gift (or pending Transaction) by your platform’s IDs.
cURL
Choosing a reference convention
For partner integrations, pick a single, stable string for yoursource value and use it consistently across every Contact and Gift you submit. Common patterns:
- Your platform name (e.g.,
"Stripe","Eventbrite","YourPlatformName") — the most readable choice. - Your platform name plus a sub-context when one partner integrates multiple data streams (e.g.,
"Acme/Donations"vs."Acme/Events") — useful when one platform sends both gift and event-attendance data.
"API" or "Import" — they make reconciliation harder when multiple integrations write to the same Virtuous organization.
Part 2: The Relationship resource
The Relationship resource models explicit connections between two Contacts — spouses, parents and children, employers and employees, board members and the organizations they serve. Relationships are distinct from the ContactIndividual structure inside a single Contact: a household Contact already groups its members internally, but a Relationship connects two separate Contacts. A typical Relationship record:| Field | Type | Description |
|---|---|---|
id | integer | Primary key of the Relationship. |
contactId | integer | The Contact this relationship is “owned by” — usually the Individual perspective. |
contactIndividualId | integer | Optionally the specific ContactIndividual on the owning Contact involved in the relationship. |
relatedContactId | integer | The Contact on the other side of the relationship. |
relatedContactIndividualId | integer | Optionally the specific ContactIndividual on the related Contact. |
relationshipType | string | The kind of relationship — see Discovering relationship types. |
notes | string | Free-text notes about the relationship. |
Discovering relationship types
The set of validrelationshipType values is configured per organization. Discover them with:
cURL
Spouse, Parent, Child, Sibling, Employer, Employee, Board Member, and Family, but the authoritative list comes from the endpoint.
Working with Relationships
The endpoints follow standard CRUD patterns:| Endpoint | Use |
|---|---|
GET /api/Relationship/ByContact/{contactId} | List all relationships for a Contact. Paginated. |
GET /api/Relationship/{relationshipId} | Retrieve a single Relationship. |
POST /api/Relationship | Create a new Relationship between two Contacts. |
PUT /api/Relationship/{relationshipId} | Update an existing Relationship. |
DELETE /api/Relationship/{relationshipId} | Delete a Relationship. The Contacts themselves are not affected. |
GET /api/Relationship/Types | Discover the valid relationshipType values for this organization. |
When to use Relationships
Most partner integrations do not need to interact with Relationships directly. The resource is most relevant for:- Wealth screening and major-gift integrations — tracking the connections between a major donor and the affiliated organizations they influence.
- Corporate giving integrations — linking corporate Contacts to the individual contacts at those corporations.
- Family giving programs — modeling parent-child or extended-family relationships when those are tracked separately from household structures.
Part 3: Other relationship patterns in the data model
Beyond the explicit Relationship resource, CRM+ uses three implicit relationship patterns:Hierarchical — parent and child
Projects can be organized in a parent-child hierarchy through theparentId field. A sub-project rolls up to its parent for reporting purposes. See Funds, Campaigns, and Designations.
Aggregating — one-to-many
Several resources have one-to-many aggregate relationships:| Container | Contents |
|---|---|
| Contact | ContactIndividuals, ContactAddresses, Gifts, RecurringGifts, Pledges, Notes, Tags |
| Gift | GiftDesignations, GiftPremiums, PledgePayments |
| ContactIndividual | ContactMethods |
| Project | Sub-Projects, GiftDesignations (via the Gifts that fund the Project) |
GET /api/Contact/{contactId} returns the Contact plus its ContactIndividuals and addresses; a GET /api/Gift/{giftId} returns the Gift plus its designations and premiums.
Reference — single foreign keys
The most common pattern: one record references another via a single foreign key field.Gift.contactId → Contact.id; GiftDesignation.projectId → Project.id; RecurringGift.contactId → Contact.id. These references are how your integration navigates from one record to another via GET /api/{Resource}/{id} calls.
Where to go next
Transactions
How external reference identifiers drive Transaction matching and idempotency.
Contacts
The Contact resource — where
contactReferences[] lives.Statuses and Lifecycle States
The next concept page — lifecycle flags across Contacts, Projects, RecurringGifts, and Pledges.
Build a Two-Way Sync
A workflow that depends heavily on stable external references in both directions.