updated_at, so polling Users alone misses a significant class of “user activity” events.
If you haven’t yet, skim the Polling Overview for the core polling pattern.
When to use this workflow
The baseline pattern
The simplest user-change polling worker:JavaScript
Distinguishing new from modified users
updated_after returns both newly-created and modified users. Sometimes you want to treat them differently — fire a welcome email on creation, fire an update event on modification.
The distinction: for newly-created users, created_at equals updated_at (or is very close). For updates, updated_at > created_at.
JavaScript
Why this works (and why it’s approximate)
The heuristic assumes that creating a user producescreated_at and updated_at simultaneously (with sub-second resolution). For most cases this is correct.
Edge cases:
- A user created and then immediately modified within the same poll window — both
created_atandupdated_atare recent, but they’re not equal. The heuristic might miss the “created” event and treat it as an update. - Bulk imports where many users are created in batch — they may all share the same
created_atbut have slightly differentupdated_at.
JavaScript
The participation caveat
The most important thing to understand about User polling: new participations do not advance the User’supdated_at.
This is the central polling caveat. Polling
/users?updated_after=X will not detect new volunteer activity.
Why this matters
A partner integration that promises “we’ll detect when your volunteers serve” cannot deliver on that promise via User polling alone. The integration architecture needs to account for this gap.What to do instead
For detecting new participations, three options:Option A: Poll GET /users/{id} for each user
After detecting a user change via the list endpoint, fetch detail to see their full participation list:
JavaScript
Option B: Periodic full participation scan
On a slower cadence (daily, weekly), iterate all users and check their participations:JavaScript
Option C: Poll Project Dates instead
If your integration mainly needs participation data for specific Projects, poll the Project Dates and pull participants from there:JavaScript
Combining updated_after with other filters
The polling pattern can be narrowed with additional filters when not all users need processing:
Poll only verified users
JavaScript
user_status as a server-side filter, so this is client-side filtering — the API returns all updated users, and your code filters in memory. The poll still consumes rate budget for all changed users, but downstream processing is narrowed.
Poll only users with email matches
JavaScript
Detecting deletions
Polling has a fundamental gap: deleted records don’t appear in queries. If a user is deleted in VOMO, polling/users?updated_after=X won’t show them — they’re just gone.
For partner integrations that need to mirror deletions to external systems, the only path is reconciliation:
JavaScript
A subtle gotcha: “deletion” vs. “not accessible”
A user may “disappear” from/users results for reasons other than deletion:
- The user was moved to a different organization within the family
- The token’s permissions changed
- The user was banned or soft-deleted but still exists
Reading user detail during the poll
The list endpoint returns abbreviatedUserResource objects. If your integration needs the full UserDetailResource (with participations and profile_field_values), fetch detail per user:
JavaScript
When to fetch detail vs. when to skip
The list-shape vs. detail-shape decision matters for poll cost. Most integrations can use list shape for the change detection itself, fetching detail only for the subset of users where the additional fields matter.
Throttling and resource limits
Per-poll-cycle request cost on/users:
JavaScript
A reference user-change poller
A complete reference implementation incorporating the patterns above:JavaScript
Monitoring
Track these metrics per customer:
A simple “is polling healthy?” alert checks that
now - latest_checkpoint < 2 * poll_interval. Beyond that, no recent activity means polling has stalled.
Production checklist
For a User-change polling worker:- Checkpoint persisted per-customer in durable storage
- Checkpoint advanced to the latest
updated_atactually seen (not wall-clock time) - Per-user failures isolated; don’t fail whole batch on one bad record
- Failed records go to a dead-letter queue
- Rate-limit-aware throttling in place
- Distinct paths for new-user vs. updated-user processing (where business logic differs)
- Deletion detection runs as a separate (slower) reconciliation
- Participation-related workflows use a different polling strategy (Project Dates, full scans, etc.)
- Per-customer monitoring dashboards exist
- Alerts on stalled checkpoints and growing DLQ
Where to go next
Detecting Project Changes
The Project-specific polling pattern with schedule-change considerations.
Reconciliation Patterns
The slow-scan patterns for deletion detection and gap recovery.
Change Detection Best Practices
The cross-cutting patterns — checkpointing, idempotency, drift.
Users
The reference page for User fields and the upsert behavior.