participations and profile_field_values work, and the practical pattern for handling responses where the spec and live API don’t perfectly agree.
If you haven’t completed the Quickstart, start there. This page assumes you have a working token and have made at least one successful request.
What we’re building
A function that fetches a single user with full detail — name, contact info, participation history, profile field responses — and parses the response into a clean object the rest of the integration can use.JavaScript
List shape vs. detail shape
A core pattern in the Volunteer API: list endpoints return abbreviated resources; single-resource endpoints return fuller ones. For users specifically:| Endpoint | Returns | Schema |
|---|---|---|
GET /users (list) | An array of UserResource — the basic profile fields | Each user has core identity fields |
GET /users/{id} (single) | A UserDetailResource — the basic fields plus participation history and profile field responses | Includes everything in UserResource plus extensions |
⚠️ Spec gap: The OpenAPI spec’s
UserDetailResource schema only formally documents two properties (participations and profile_field_values). In practice, the live API likely also returns the base UserResource fields alongside these — id, first_name, email, etc. — making UserDetailResource a superset of UserResource, not a replacement for it.The code patterns on this page assume the superset shape. Confirm against the live API for production-critical workflows.Step 1: get a user ID
Most “fetch single user” workflows start by knowing the ID. Common ways to get one:| Source | Notes |
|---|---|
| Previous list call | GET /users returns each user’s id. Capture and use it. |
| Search by name or email | GET /users?name_like=wayne or ?email_like=bruce@wayne.example returns matching users. Take the first match (or surface for disambiguation if multiple). |
| External system | Some integrations get the VOMO user ID by some other path — a previous sync, a stored mapping, a webhook from another system. |
12345.
Step 2: fetch the user
cURL
| Element | Description |
|---|---|
data is an object (not an array) | Single-resource endpoints return a single object inside data, not a single-element array |
| Base user fields are present | first_name, email, etc. are at the top level of data alongside the detail-specific fields |
| Nested arrays for participations and profile field values | The detail response includes related records embedded in the main response |
Step 3: parse the response
A parsing helper that handles the differences between spec and live API:JavaScript
| Pattern | Why it matters |
|---|---|
?? null for optional fields | Tolerates missing fields rather than crashing on undefined.something |
hours parsing as float | Spec types it integer but live returns "4.00" — see audit finding #40 |
project_id / project_date_id parsing to int | Spec types them string but they’re IDs that join to integer-typed records elsewhere |
new Date() wrapping for ISO strings | Native Date objects are easier to work with than ISO strings in downstream code |
Step 4: handle the four-case shape
When fetching a single resource, four cases can occur:| HTTP status | What it means | Code response |
|---|---|---|
200 OK | User found and returned | Parse and return |
404 Not Found | User with that ID doesn’t exist | Return null; caller decides how to handle |
401 Unauthorized | Token invalid | Don’t retry; alert |
5xx | Transient server error | Retry with backoff |
JavaScript
Step 5: do something useful with the parsed user
A few patterns for what to do once you have the user object:Calculate total hours volunteered
JavaScript
hours parsing as float (rather than integer) matters here — a user with three participations of 1.5, 2.0, and 0.75 hours sums to 4.25, not the truncated integer 4.
Find the user’s most recent participation
JavaScript
checked_out_at descending. For users with many participations, this is more efficient than a separate query.
Display profile field values
JavaScript
Patterns for other detail-shape resources
The same pattern applies to other single-resource fetches in the Volunteer API:GET /projects/{id} returns ProjectDetailResource
Returns project metadata plus embedded data like dates, owners, and other relationships. Parse similarly to user detail.
GET /projects/date/{id} returns Project Date detail
Returns a specific occurrence of a project with the embedded participations for that date.
GET /groups/{id} returns a single group
Returns the group with its metadata. Members are fetched separately via GET /groups/{id}/members.
GET /organizations/{id} returns organization detail
Returns the organization with its full address, logo, contact info, and parent/child organization relationships.
⚠️ Spec gap: Several detail-shape endpoints —
GET /organizations, GET /organizations/{id}, GET /campaigns, GET /campaigns/{id}, GET /projects/{id}, PUT /projects/{id}, GET /projects/date/{id} — define their 200 responses with an empty schema: {} in the spec (per audit finding #4). The response shape is conveyed only through inline examples. Build parsers from the actual response shapes, treating the spec’s inline examples as a guide.What about creating or updating a user?
POST /users creates or updates a user (it’s an upsert — see audit finding #47). The request body shape:
JavaScript
- The request body uses
snake_case(consistent with the API’s overall casing). - The response distinguishes between
200(updated) and201(created) — code can detect which behavior occurred. - Matching for the upsert is typically done by
email— submitting a user with an existing email updates that user; submitting with a new email creates one.
What’s now in your toolkit
After this walkthrough, you have:- A working “fetch user by ID” pattern with the detail-shape response handled correctly
- A parser that translates the API’s snake_case fields and audit-flagged type quirks into a clean integration-friendly shape
- An error-handling pattern for the four-case shape (200/404/401/5xx)
- The pattern transferable to other single-resource fetches (
GET /projects/{id},GET /groups/{id}, etc.) - The upsert pattern for
POST /users
Where to go next
Error Handling
The full error-classification pattern for production-grade integration code.
Pagination
The pattern for reading more than one page of users.
The Volunteer Data Model
What other resources are available and how they relate.
Common Workflows
Recipes for the common tasks built on the patterns introduced here.