Skip to main content
The Volunteer API’s data model is built around volunteer engagement — Users who participate in Projects on specific Dates, organized into Groups, attached to Campaigns, owned by Organizations. This page walks through the eight resource families, how they relate, and the central Participation pattern that’s unique to volunteer management. The audience is partner integration engineers and architects building or designing against the Volunteer API. Understanding this model first prevents a lot of confusion downstream.

The eight resource families

The eight resource families: Two patterns to notice from this table:

The central pattern: User ↔ Participation ↔ Project Date

The most important relationship in the model is the Participation triangle: When a volunteer (User) participates in a specific scheduled occurrence (Project Date) of a recurring opportunity (Project), a Participation record is created. The Participation captures: Participations are how the API answers questions like:

Reading participations

There’s no top-level GET /participations endpoint. Participations are always returned embedded in another resource’s response: For partner integrations that need a flat “all participations” view, the typical pattern is:
  1. List all users via GET /users with pagination.
  2. For each user, GET /users/{id} to get their participations.
  3. Flatten across all users.
This is N+1 — one initial query plus one per user. For large customers, it’s expensive. See API Performance Tips for the optimization patterns.
⚠️ Spec gap (audit #40, #41): The ParticipationResource schema types hours as integer and project_id / project_date_id as string. The live API returns fractional hours (e.g., "4.00") and integer IDs. Code should parse hours as a float and IDs as integers regardless of the spec’s type declaration.

Project vs. Project Date

A common source of confusion: the difference between a Project and a Project Date.

Project = the template (the “what”)

A Project is the volunteer opportunity itself — what it is, what’s being asked of volunteers, what skills are needed, what the organization wants to accomplish. It’s a long-lived record that persists across many actual occurrences.
The Project has fields like name, description, organization, address, age_limit, privacy, categories, and so on.

Project Date = the specific occurrence (the “when”)

A Project Date is one specific scheduled occurrence of a Project. The same Project can have dozens or hundreds of Project Dates over its lifetime.
The Project Date has fields like id, starts_at, ends_at, participant_count, and the embedded participants for that date.

In the API

⚠️ Spec gap (audit #34): The endpoint GET /projects/date/{id} uses a verb-like singular noun (date) in the path, which is inconsistent with REST conventions. The audit recommends renaming to GET /projects/{projectId}/dates/{dateId}. The current path is what works against the live API today; the alternative path may exist in a future v2.

Why this matters for integrations

A common bug: querying /projects/{id} expecting to get the participants for an upcoming shift, then being surprised that it returns the template’s metadata instead. The participants are on the Project Date, not the Project.

Organization hierarchy: the “organization family”

Organizations in VOMO can have parent-child relationships. The customer’s primary Organization may have children — sub-organizations like local chapters, regional offices, or affiliated nonprofits — and may itself be a child of a larger umbrella organization.

What this enables

  • A single API token can be scoped to access the parent organization and its children.
  • Reports and aggregations span the full organization family by default.
  • Projects, Campaigns, and Groups are owned by specific organizations within the family.

What the API exposes

⚠️ Spec gap (audit #25, #26, #27): The Organization endpoints have empty schema: {} in the spec — the response shape is documented only through inline examples. There is no OrganizationResource component schema. The “organization family” concept is mentioned in the endpoint summary but isn’t formally documented. Build parsers from the actual response shapes.

Per-resource organization attribution

Most resources track which organization in the family they belong to: When the partner integration is reading data, the attribution lets them route or filter records to the right organization within the family.

Forms: data-collection attached to Projects

Forms in VOMO are data-collection templates — waivers, signups, profile fields, application questions. Volunteers complete Forms; the completion is captured as a Form Completion. The relationships:

Where Forms live

Forms are attached to Projects in the admin UI; the partner integration reads them through the endpoints above. Common use cases include waivers (signed once per volunteer), event-specific signups (additional info beyond standard Project signup), and post-event surveys.

Form types

The form_type field on FormResource has documented enum values, though the audit (#54) flags that only "PROJECT" is documented and other types likely exist.

Certificates: training and achievements

Certificates represent training credentials, badges, or other achievements that volunteers earn. Common uses include:
  • Required safety training (e.g., food handler certification for food bank volunteers)
  • Background check completion
  • Specialized role qualifications (e.g., team leader training)
  • Completion badges for milestone hours
⚠️ Spec gap (audit #14): The same resource is referred to as “certificate”, “certification”, and “certificates” in different places in the spec — the path is /certificates, the tag is Certifications, the operationId is listCertifications, and the schema is CertificateResource. The naming will be reconciled in a future spec revision. For partner integrations today, use the path (/certificates) and the schema name (CertificateResource) as your reference points.
Certificate earning is recorded per-user; the User Detail response (GET /users/{id}) typically includes earned certificates alongside other user data.

Groups: cross-cutting User collections

Groups in VOMO organize Users into collections — teams, affinity groups, chapter members, etc. Unlike Projects (which represent opportunities), Groups represent stable collections of people that persist independent of specific events. The relationships: Groups have the most write-heavy surface of any Volunteer resource: This makes Groups the canonical “build a volunteer team programmatically” resource. Common patterns include:
  • Syncing external team rosters into VOMO Groups
  • Building Groups based on participation criteria (e.g., “active volunteers in 2024”)
  • Creating event-specific Groups for managing rosters
⚠️ Spec gap (audit #21, #22): POST /groups returns 200 (not 201 per HTTP convention for resource creation). DELETE /groups/{id} returns 200 (not 204 per convention for empty-body deletes). These are spec-confirmed behaviors; integrations should code for what the API actually returns, not what HTTP conventions suggest.

Campaigns: longer-running initiatives

Campaigns group multiple related Projects under a single umbrella initiative. They represent the customer’s longer-term goals or themes:
Campaigns are read-only from the API — they’re managed in the VOMO admin UI. Partner integrations use them for reporting and attribution (“how is the Summer Outreach campaign performing?”).
⚠️ Spec gap (audit #4, #13): The Campaign endpoints have empty schema: {} in the spec, and CampaignResource description erroneously reads “A VOMO Project.” Build parsers from actual response shapes.

What’s NOT in the API

Several resource types that exist in VOMO but aren’t currently exposed in the API: For partner integrations needing to record participations programmatically, coordinate with VOMO’s admin team for alternative paths — typically through Group management or scheduled imports. See Understand Write Limitations for the complete picture.

ID stability and matching

Across the API, several patterns govern how IDs work: User matching for upsert (POST /users) is done by email — submitting a user with an existing email updates that user; submitting with a new email creates a new one. See Users: upsert behavior.

Cross-API mapping

For partners integrating Volunteer alongside CRM+ or Raise, the conceptual mappings: Note these are conceptual analogs, not exact matches. A Volunteer User is roughly equivalent to a CRM+ Contact in role (the person record), but the field shapes and write paths differ significantly. For partner integrations syncing across all three APIs, the typical pattern is:
  • Match by email when joining records across APIs
  • Treat each API’s records as authoritative for their own domain (User in Volunteer, Contact in CRM+, Donor in Raise)
  • Use partner-side mapping tables when the same person needs distinct records in each system
See the Volunteer Recipes for examples of cross-API integration patterns.

Where to go next

Users

The User resource reference in depth — fields, filters, upsert behavior.

Projects and Project Dates

The Project (template) vs. Project Date (occurrence) distinction in full detail.

Groups

The most write-heavy resource — Group management and members.

Understand Write Limitations

The explicit list of what the API can and can’t do.
Last modified on May 22, 2026