Skip to content
Embedded Care
Guides

Group Member Sync

Submit your member roster for a group. Vitable provisions accounts and starts plan subscriptions asynchronously.

This guide picks up where Group Onboarding leaves off. Once you have a group and know which plan_id to subscribe members to, you can submit the group’s roster via POST /v1/groups/{group_id}/members/sync. The endpoint accepts the complete current roster for one group, validates it, and queues it for asynchronous processing.

Before you begin, make sure you have a valid API key. See Authentication for details.

Send the complete current roster as an array of members:

Terminal window
curl -X POST https://api.vitablehealth.com/v1/groups/{group_id}/members/sync \
-H "Authorization: Bearer $VITABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"members": [
{
"reference_id": "mem-001",
"first_name": "Maria",
"last_name": "Garcia",
"date_of_birth": "1990-05-15",
"phone": "5555550101",
"plan_id": "pln_aBcDeFgHiJkLmNoPqRsTuV",
"address": {
"address_line_1": "123 Main Street",
"city": "Pittsburgh",
"state": "PA",
"zipcode": "15222"
},
"email": "maria@beanworks.example.com"
},
{
"reference_id": "mem-002",
"first_name": "James",
"last_name": "Chen",
"date_of_birth": "1985-11-22",
"phone": "5555550102",
"plan_id": "pln_aBcDeFgHiJkLmNoPqRsTuV",
"address": {
"address_line_1": "456 Oak Avenue",
"address_line_2": "Apt 4B",
"city": "Pittsburgh",
"state": "PA",
"zipcode": "15201"
}
}
]
}'

A successful response is 202 Accepted with an acceptance receipt:

{
"data": {
"request_id": "grpmsr_pQr456sTu789vWxYzAbCd",
"group_id": "grp_zYxWvUtSrQpOnMlKjIhGfE",
"accepted_at": "2026-03-25T14:30:00+00:00"
}
}

Keep the request_id. It’s how you’ll inspect the per-member results once processing finishes — there are no webhooks for this flow, so polling the sync request is the only way to know how each row was applied.

FieldTypeRequiredRules
reference_idstringYes1–255 chars. Must be unique within the payload. Used to match existing members across syncs.
first_namestringYesMax 255 chars.
last_namestringYesMax 255 chars.
date_of_birthstringYesISO 8601 date (e.g. 1990-05-15).
phonestringYes10-digit US number, digits only (5551234567).
plan_idstringYesA pln_ ID available to your organization. See Group Onboarding — Step 1.
addressobjectYesSee address fields below.
address.address_line_1stringYesMax 255 chars.
address.address_line_2stringNoMax 255 chars.
address.citystringYesMax 255 chars.
address.statestringYes2-letter US state or territory code (PA, CA, etc.).
address.zipcodestringYesUS ZIP.
emailstringNoValid email address.

Limits: Each reference_id must be unique within the payload. Contact your account manager before sending payloads larger than a few thousand rows.

See the Submit Group Member Sync endpoint for the full request and response schema.

After your sync is accepted, Vitable processes each member asynchronously:

  1. Triage. Vitable compares the incoming reference_id set against the members currently subscribed to your organization’s plan in this group.
    • References present in the payload but not currently subscribed → add
    • References currently subscribed but not in the payload → remove
    • References present in both → no-op (existing subscription preserved)
  2. Add. For each new reference, Vitable provisions (or re-uses an existing) account, attaches it to the group, and starts a plan subscription on the requested plan_id. A new member can authenticate immediately via the passwordless flow — see Authentication.
  3. Remove. For each missing reference, Vitable ends the member’s plan subscription. The member’s account is preserved so prior care history stays accessible; they simply are no longer subscribed.
  4. Complete. Per-member outcomes are recorded on the sync request as results. The request_id returned above identifies that record.

Poll GET /v1/groups/{group_id}/members/sync/{request_id} to read the status of a previously-submitted sync:

Terminal window
curl -X GET https://api.vitablehealth.com/v1/groups/{group_id}/members/sync/{request_id} \
-H "Authorization: Bearer $VITABLE_API_KEY"

While processing is in flight, completed_at and results are both null. Once processing finishes, completed_at is a timestamp and results is an object with three lists:

{
"data": {
"request_id": "grpmsr_pQr456sTu789vWxYzAbCd",
"group_id": "grp_zYxWvUtSrQpOnMlKjIhGfE",
"accepted_at": "2026-03-25T14:30:00+00:00",
"completed_at": "2026-03-25T14:30:08+00:00",
"results": {
"added_group_member_ids": ["grpmbr_lMn345oPq678rSt"],
"removed_group_member_ids": [],
"failures": [
{
"reference_id": "mem-003",
"operation": "add",
"reason": "Plan pln_… not found"
}
]
}
}
}

A member appearing in failures was not applied. The rest of the batch still processed normally; failures do not abort the sync.

Subsequent syncs follow the same model — submit the complete current roster every time.

  • Add a new member: include their record (with a new reference_id) in the next sync.
  • Update an existing member: keep their reference_id stable and submit the new values. Field-level updates are applied to the existing record.
  • Remove a member: omit their reference_id from the next sync. Their subscription is ended; their account is preserved so prior care history stays accessible.
  • Re-add a removed member: include them again in a later sync. Their account is reused; a fresh subscription is started.
  • Remove everyone: submit { "members": [] }.
  • 400 on submit — missing or invalid field: the payload failed synchronous validation. Common causes: a required address field missing, phone not exactly 10 digits, invalid state code, duplicate reference_id within the payload, or plan_id that isn’t a valid UUID. The response message lists every failing field.
  • 202 accepted, but a member is in failures with "Plan … not found": the plan_id for that member is not linked to your organization. Re-check GET /v1/plans for the IDs you can use.
  • 202 accepted, but a member is in failures with "Member already has an active subscription!": the matched member already holds an active plan subscription under a different organization. Their existing subscription is preserved untouched; the sync rejects the add. Coordinate with the other organization to end their subscription before re-syncing.
  • Member added, but they can’t log in: account provisioning is asynchronous and continues briefly after the sync completes. If the passwordless flow returns “user not found” right after a sync, wait a few seconds and retry.
  • results is still null long after submit: the worker may be processing a backlog. If it stays null for more than a few minutes on a small batch, contact Vitable support with the request_id.