Skip to main content
The Volunteer API is at v1 — URL-versioned via the /v1/ segment in the base URL (https://api.vomo.org/v1). A v2 overhaul will eventually arrive, addressing many of the audit-flagged quirks (type inconsistencies, naming inconsistencies, anonymous schemas) accumulated in v1. When that happens, integrations that handled v1’s quirks defensively will migrate gracefully; integrations that depended on v1’s exact behavior will break. This page covers the patterns that prepare integrations for API evolution: defensive parsing, version-aware clients, feature flags for behavior changes, deprecation handling, and the partner-side schema evolution practices that keep integrations running through inevitable change.

The eventual v2 reality

The current v1 API has documented quirks that v2 will likely address: These are documented in the audit findings throughout the docs (see Concepts and individual workflow pages). Many integrations have built workarounds for them; v2 will allow those workarounds to be removed. But between now and v2, your integration runs against v1. And during the transition, your integration may need to support both. This page is about how.

Principle 1: defensive parsing at every boundary

The single most valuable practice for surviving API evolution: never trust the API’s response shape. Parse defensively at the boundary; produce a clean internal representation; quarantine the API’s quirks in one place.

The pattern

JavaScript
The parser is the only place that knows about v1’s quirks. Application code receives clean, typed, normalized data — and doesn’t care whether the API returns hours as a string or number.

When v2 ships

JavaScript
The migration is localized — only the parser changes. Application code continues working without touching.

Principle 2: version-aware clients

Plan for v1 and v2 to coexist during the transition. Use a version-aware client that knows about both:
JavaScript

Per-customer version selection

For staged migration, version selection becomes per-customer:
JavaScript
Some customers can be on v2 while others stay on v1, allowing gradual migration. The application code stays oblivious — the client and parser handle the version differences.

Principle 3: ignore unknown fields

When the API returns fields you don’t recognize, ignore them. Don’t fail; don’t log them as errors; just skip:
JavaScript
If the API adds a new field (e.g., v2 adds last_login_at), your integration continues working — it just doesn’t surface the new field until you decide to. This is the forward-compatible reading principle: be conservative in what you send, liberal in what you accept.

Don’t fail on additions

The wrong thing to do:
JavaScript
This breaks every time the API adds a new field. Customers see the integration fail; the partner has to ship a release just to acknowledge the new field exists.

Optional: log unknown fields for awareness

For debugging help (during v2 transition especially), log unknown fields at a low level:
JavaScript
The log entry doesn’t fail the operation but surfaces what’s new. Useful for awareness; not load-bearing.

Principle 4: feature flags for API behavior changes

When migrating from v1 to v2 (or any time you change how the integration handles API responses), wrap the change in a feature flag:
JavaScript
Flagged rollout: At each phase, monitor: error rates, processed-record counts, reconciliation gap rates. If anything degrades, roll back the flag (no code deploy needed).

Principle 5: schema evolution on the partner side

Your own data model evolves too — fields get added, types change, columns are deprecated. Plan for the partner-side schema to evolve in lockstep with VOMO’s changes:

Pattern: additive changes only

Whenever possible, add columns; don’t remove them. Removing a column breaks queries that depend on it.
Removal should follow a deprecation cycle: mark as deprecated, migrate consumers off, then remove.

Pattern: nullable new columns

New columns should be nullable initially:
Backfill data before adding NOT NULL. Or accept nullable forever — sometimes the right answer.

Pattern: schema versioning

For complex schemas, track the migration version:
This is a standard pattern (and most ORMs handle it). It lets you reason about which version of the schema is currently deployed in each environment.

Principle 6: deprecation handling

When VOMO eventually marks a field or endpoint as deprecated (typical pattern: Deprecation header or Sunset header per RFC 8594), your integration should:
  1. Detect the deprecation in API responses
  2. Log it for awareness
  3. Schedule migration before the sunset date
  4. Verify the migration before the sunset takes effect

Pattern: detect deprecation headers

JavaScript
A central record of all observed deprecations becomes the migration backlog.

Pattern: scheduled migration with safety margin

For a deprecated endpoint with a sunset date, migrate well before: If you wait until the last 30 days, you’re under pressure and prone to bugs. Earlier migration leaves room to handle surprises.

Principle 7: contract testing

For partner integrations, run regular tests against VOMO that verify the integration’s assumptions about response shapes:
JavaScript
Run these tests:
  • Nightly against the production API (with a test customer’s token)
  • As part of CI for any release that touches the integration
When VOMO ships v2, these tests will surface incompatibilities — expect(typeof hours === 'number') would now pass without the string fallback. You’d see the change immediately and could plan the migration.

Don’t test in production with real data

Use a dedicated test customer / test organization for contract tests. Don’t run them against a real customer’s data — both for privacy and for stability (test runs could affect real data if the API behaves unexpectedly).

Principle 8: graceful handling of schema differences

Your integration’s schema and the API’s schema will inevitably diverge. Build the partner side to accommodate either:

Pattern: optional source fields

If a downstream system requires a field that VOMO sometimes returns as null:
JavaScript
The fallbacks let your integration produce valid output even when VOMO provides partial data.

Pattern: rejection vs. degradation

For records that can’t be sanely processed (missing required fields, malformed data), choose between rejection (DLQ) and degradation (process with defaults):
JavaScript
Decide per-field whether absence is fatal or tolerable. Document the decisions.

Principle 9: documentation of assumptions

Every assumption your integration makes about the API should be documented. When the API changes, the documentation tells you what to re-verify. A simple convention: a per-integration API_ASSUMPTIONS.md file:
When a v2 migration is on the horizon, this doc is the migration checklist — every assumption that v2 changes needs corresponding integration code update.

Principle 10: graceful failure modes for API changes

When the API does something unexpected, what does your integration do? The general principle: fail loudly enough to be detected, but quietly enough to not crash the whole integration. Per-record failures go to DLQ; systemic patterns trigger alerts; the integration continues serving the customers it can.

Migration playbook for v2

When VOMO v2 lands, the migration follows a predictable pattern:

Phase 1: assess (week 0-2)

  • Review v2’s changes against API_ASSUMPTIONS.md
  • Categorize: backward-compatible additions, type fixes, structural changes
  • Estimate effort per category

Phase 2: prepare (week 2-6)

  • Update the parser layer to handle both v1 and v2 response shapes
  • Add feature flag for v2 client selection per customer
  • Update contract tests to verify v2 shapes
  • Run contract tests against v2 with a test customer

Phase 3: pilot (week 6-8)

  • Migrate internal test customer to v2
  • Run for 1-2 weeks
  • Monitor: error rates, reconciliation gaps, processing rates

Phase 4: progressive rollout (week 8-20)

  • 1 friendly customer → 10% → 50% → 100%
  • At each step, monitor metrics for ~1 week before advancing

Phase 5: cleanup (week 20+)

  • Remove v1 code paths
  • Update API_ASSUMPTIONS.md
  • Update documentation
  • Celebrate
The timeline scales with integration complexity. A simple read-only sync may compress to weeks; a complex bidirectional integration may take months.

What’s worth defending against vs. accepting

Not every potential API change deserves defensive code. The pragmatic decision matrix: The general rule: defend against subtle changes that could silently produce wrong output; accept the cost of explicit migration for major changes that are obvious when they happen.

Final principle: design for change

The deepest defense against API evolution is making the integration easy to change. Practices that support this: An integration with these practices doesn’t dread API changes — it absorbs them. An integration without them treats every change as a crisis. The difference is months of cumulative engineering work, paid out one improvement at a time.

Where to go next

Sync Architecture Patterns

The architectural patterns that make change manageable.

Security and Credential Management

The security patterns that complement versioning hygiene.

Data Modeling

The data model that allows partner-side schema evolution.

Error Recovery Patterns

The error-handling patterns that absorb API changes gracefully.
Last modified on May 22, 2026