Skip to navigation

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.

Submit a Member Sync

Send the complete current roster as an array of members:

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.

Per-Member Fields

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.

Member sync replaces the group’s active roster. Any member previously synced into this group but omitted from the new payload will have their subscription ended and will be dropped from the group. This is not an append operation. Always submit the complete current roster.

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.

What Happens Next

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.

There are no webhooks for group member sync. Neither completion of the batch nor success/failure of an individual member triggers an event. To verify outcomes, poll the sync request endpoint and inspect the results payload.

Inspecting Results

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

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.

Updating, Adding, and Removing Members

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": [] }.

Treat your reference_id as a stable, durable identifier for the member on your side (e.g. your HRIS row ID). Changing it across syncs causes Vitable to treat the row as a new member — ending the old subscription and starting a new one with broken continuity.

Troubleshooting

  • 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.