Member Sync
How member sync works under the hood — the replacement model, reference matching, async processing, and how to read the results.
Member sync is the single endpoint you use to add, update, and remove members within a group. You send the complete current roster for one group, and Vitable reconciles the existing membership against what you submitted: anything new is added, anything missing is removed, anything unchanged is left alone.
You send one POST /v1/groups/{group_id}/members/sync request containing your members, and Vitable processes them asynchronously. The HTTP response is an acceptance receipt — not the final result. Final outcomes appear on the sync request itself once processing completes.
This page covers the replacement model, how members are matched across syncs, the async flow, and how to read results — including partial failures.
The Replacement Model
Every sync replaces the set of members currently subscribed to the group’s plans. Vitable treats the payload as the new truth and reconciles by reference_id:
Sync is not an append. If you submit { "members": [A, B] } and the group already contains [A, B, C], member C is removed. To add a single new member without affecting the rest, you must submit the complete roster — every existing member plus the new one.
An empty members: [] is a valid sync. It removes everyone in the group.
How References Are Matched
reference_id is your stable, partner-owned identifier for a member. Vitable uses it to recognize the same person across syncs.
Pick a reference_id that is stable for the life of the member in your system
— your HRIS row ID, contract member number, or customer ID. Avoid identifiers
that can change (email addresses, names), or that get reissued.
Within a single payload, every reference_id must be unique. Sending the same reference_id twice in one sync fails synchronous validation with HTTP 400.
When a new reference_id is added, Vitable will re-use an existing person record if the contact details match someone it already knows — typically by email and date of birth. The member retains their prior care history; only the group membership and the plan subscription are new.
The Async Flow
Flow summary:
- You submit a roster for one group.
- Vitable validates the payload structure and returns
202with arequest_id(grpmsr_…) andaccepted_at. - Vitable reconciles your payload against the group’s current roster and processes each add/remove asynchronously.
- When processing is complete, the sync request’s
resultsfield is populated with per-member outcomes.
The 202 response confirms Vitable accepted your payload for processing. It
does not mean any members have been added or removed yet. Always inspect
the sync request’s results to confirm outcomes.
There are no webhooks for member sync. Neither completion of the batch nor
the success/failure of an individual member fires an event. To track outcomes,
poll GET /v1/groups/{group_id}/members/sync/{request_id} and read its
results.
Results: Reading What Happened
To inspect the outcome of a sync, call:
Until processing finishes, completed_at and results are both null. Once processing completes, completed_at is a timestamp and results is an object with three lists:
Each failure entry includes the reference_id you submitted, the operation Vitable was attempting (add or remove), and a human-readable reason.
Idempotency and Repeated Syncs
A sync that matches the group’s existing roster exactly is a no-op — no members are added, none are removed, no failures are recorded. This makes it safe to re-submit the same roster:
- After a network error, if you don’t know whether the previous request landed, you can safely resubmit.
- On a schedule, you can run periodic full-roster syncs (e.g. nightly) to keep Vitable in lockstep with your source of truth.
The only thing a re-submitted sync changes is the audit trail: every accepted submission creates a new request_id, even if zero members move.
Partial Failures
A sync that is accepted (202) does not guarantee every member processes successfully. The two most common reasons a single member ends up in failures are:
plan_idnot available to your organization. The plan UUID isn’t linked to your org. Failures cite"Plan {id} not found". Re-checkGET /v1/plansfor the IDs you can use.- Member already has an active subscription elsewhere. The matched member holds an active plan subscription under a different organization. Vitable preserves their existing subscription untouched and rejects the add with
"Member already has an active subscription!". Coordinate with the other organization to end the existing subscription before re-syncing.
Other rows in the same sync are unaffected. A failure list with one entry means one member didn’t apply; the other N–1 did.
Always inspect results.failures before reporting a sync as “done” in your
own UI or audit log. A 202 plus a non-empty failures array means partial
success.
Synchronous Validation
These errors come back immediately as HTTP 400 — no processing occurs:
- A required field is missing on any member (
reference_id,first_name,last_name,date_of_birth,phone,plan_id,address). phoneis not a 10-digit US number.addressis missing a required field (address_line_1,city,state,zipcode) orstateis not a valid 2-letter US state/territory code.plan_idis not a UUID.- Two members share the same
reference_idwithin the payload. - The
group_idin the URL is malformed or does not belong to your organization.
The 400 response lists every failing field. Fix and resubmit; nothing changes in the group until a 202 is returned.
Related Concepts
- Groups — what a group is and how to organize them.
- Member Lifecycle — what happens to a member after they’re synced.
Related API Endpoints
POST /v1/groups/{id}/members/sync— Submit a member syncGET /v1/groups/{id}/members/sync/{request_id}— Retrieve a sync request’s status and resultsGET /v1/plans— List plans available to your organization

