Skip to main content
This page walks through a more substantive API call than the bare-minimum Quickstart — fetching a single user by ID and parsing the rich detail response that comes back. By the end, you’ll understand the difference between list-shape and detail-shape resources, how nested fields like 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
The pattern applies to most “fetch a single record” workflows across the API. Once you understand it for users, it transfers directly to projects, groups, and other resources.

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: This pattern is common in REST APIs designed around resource efficiency — list endpoints stay fast by returning only the fields most callers need, and single-resource endpoints provide the deep dive when needed.
⚠️ 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: For this walkthrough, assume you have a user ID — say 12345.

Step 2: fetch the user

cURL
A typical successful response (truncated):
Three things to notice about the response:
The OpenAPI spec documents data for GET /users/{id} as type: array (per audit finding #50), but the live API returns a single object as shown above. Code should expect an object, not an array. If your code is generated from the spec, it may need manual adjustment.

Step 3: parse the response

A parsing helper that handles the differences between spec and live API:
JavaScript
Three patterns this parser gets right:

Step 4: handle the four-case shape

When fetching a single resource, four cases can occur:
JavaScript
The classification matters because retry logic depends on it. See Error Handling for the broader pattern.

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
The 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
This sorts the embedded participations by checked_out_at descending. For users with many participations, this is more efficient than a separate query.

Display profile field values

JavaScript
The profile field values are keyed by label (the field’s display name) — useful for displaying or filtering on custom data the customer has set up.

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
Notable points:
  • The request body uses snake_case (consistent with the API’s overall casing).
  • The response distinguishes between 200 (updated) and 201 (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.
See Create or Update a User for the full upsert workflow.

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
This is enough to build most read-oriented integrations. The next step is wiring up multi-record reads with pagination, then choosing the right error-handling strategy.

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.
Last modified on May 22, 2026