Sync Patterns

Partners and RCMS keep data in sync using two mechanisms that complement each other: webhooks push events when something changes; the API serves on-demand reads and backfills. This page covers the recommended pattern, expected latency, idempotency, and how to recover from outages.

The recommended pattern

  1. Subscribe to webhooksfor the events you care about. This is your primary change feed — you get pushed updates in seconds.
  2. Fetch full resources via APIafter receiving an event. The webhook payload tells you “client 260 was discharged;” a follow-up GET /v1/clients/260 gives you the complete, post-change state.
  3. Periodically reconcile with a delta sync— once a day is usually enough. List endpoints accept ?updated_after= so you can pull only what's changed since your last check.

Webhooks are push. API reads are pull. Use both.

Expected latency

EventWebhook fires within
Client enrolled / discharged / updated30 seconds
Assessment submitted30 seconds
Assessment scored1–3 minutes (scoring runs asynchronously)
Assessment due soon / overdueWithin 1 hour of the state change
Staff created / updated / deactivated30 seconds

API reads are near real-time; data written to RCMS is visible on the next GET to that resource within a few seconds.

Delta sync with updated_after

Every list endpoint accepts an updated_after query parameter (ISO-8601 timestamp). Pass the timestamp of your last successful sync to get only the records modified since.

# Nightly reconciliation job (pseudo-code)
last_sync_at = read_state("rcms_last_sync_at")

url = f"https://api.measurerecovery.com/v1/clients?updated_after={last_sync_at}"
while url:
    response = http_get(url, headers={"Authorization": f"Bearer {API_KEY}"})
    for client in response["data"]:
        upsert_into_partner_db(client)
    url = response["meta"]["next_url"]  # null when no more pages

write_state("rcms_last_sync_at", now_iso())

updated_afteris inclusive — running the same timestamp twice will re-fetch boundary records. Upsert using the resource's id so repeats are harmless.

Idempotency keys

Every write endpoint (POST /clients, POST /staff, etc.) accepts an Idempotency-Key header. If RCMS sees the same key within 24 hours, it returns the original response instead of creating a duplicate.

curl -X POST https://api.measurerecovery.com/v1/clients \
  -H "Authorization: Bearer rcms_live_xxxxxxxx" \
  -H "Idempotency-Key: partner-enrollment-2026-04-19-abc123" \
  -H "Content-Type: application/json" \
  -d '{ "first_name": "...", ... }'

Recommendation: use your own internal ID for the record as the idempotency key (e.g., onestep-client-12345). If a network blip causes you to retry, RCMS won't create a second client.

Outage recovery

If your webhook endpoint is down

If RCMS is down (rare)

Full rebuild / onboarding a new partner app

If you're starting from scratch (e.g., new database, or first sync after signing on): run the list endpoints without updated_after to pull everything, page by page. Then record the current timestamp and switch to the webhook + delta pattern.

Per-resource sync recommendations

ResourcePrimaryBackupReconcile
OrganizationsWebhook: organization.*GET /organizations?updated_after=Weekly
StaffWebhook: staff.*GET /staff?updated_after=Daily
ClientsWebhook: client.*GET /clients?updated_after=Daily
Assessment scoresWebhook: assessment.scoredGET /clients/:id/assessment-statusDaily
Client notifications (reminders)Webhook only (assessment.due_soon / overdue)n/a (partner owns delivery)

“Primary” is how you should normally get updates. “Backup” is the fallback when webhooks are unavailable. “Reconcile” is the recommended delta sync cadence to catch anything webhooks missed.

Common mistakes to avoid

Next steps

Webhooks

Event types, signature verification, delivery semantics.

Data Model

Organizations, staff, clients — required fields and lifecycle.