Atlas Roster
Invite people to share with an Atlas organization and automate their roster lifecycle.
Roster operations manage people invited through Atlas. They are separate from /v1/users, which manages API-created users and their stored health data. Roster operations require a live API key; sandbox keys return 409 live_environment_required.
Invite a Roster Member
/v1/atlas/roster/invitationsCreates and sends a 14-day invitation. The person chooses whether to share their Sonar data with the organization.
{
"email": "jordan@example.com",
"full_name": "Jordan Kim"
}A successful request returns 201 Created:
{
"id": "8ab89a…",
"email": "jordan@example.com",
"full_name": "Jordan Kim",
"status": "pending",
"expires_at": "2026-10-03T10:00:00.000Z",
"accept_url": "https://app.sonarhealth.co/trainee-invite?token=…"
}Creating another invitation for the same email revokes the prior pending invitation and sends a new one. This endpoint does not accept an idempotency key; retain the returned invitation ID before retrying.
Invitations return 403 roster_invitations_disabled when the organization’s product configuration does not allow invitations, or 402 billing_add_trainee_blocked when another active roster seat cannot be added.
Read Invitation Status
/v1/atlas/roster/invitations/{id}Returns pending, accepted, revoked, or expired. subject_id is populated after acceptance.
{
"id": "8ab89a…",
"status": "accepted",
"subject_id": "7e4e91a5-1e4f-4fc2-903c-251046d2a4d3"
}Revoke an Invitation
/v1/atlas/roster/invitations/{id}Revokes a pending invitation and returns 204 No Content.
Repeating a revoke, or revoking an expired invitation, also returns 204. An accepted invitation returns 409 invitation_already_accepted; manage the accepted roster member instead.
Archive or Reactivate
/v1/atlas/roster/{id}Changes whether an invited person is active in the Atlas roster.
{ "status": "archived" }Archiving removes the person from the active roster and active-seat count without deleting their Sonar account or health data. The sharing relationship is retained so the member can be restored. Reactivating may return 402 billing_add_trainee_blocked when no active seat is available.
The response is the current roster member:
{
"id": "7e4e91a5-1e4f-4fc2-903c-251046d2a4d3",
"display_name": "Jordan Kim",
"email": "jordan@example.com",
"source": "b2c",
"status": "archived",
"created_at": "2026-09-19T10:00:00.000Z",
"archived_at": "2026-09-19T12:00:00.000Z"
}Setting the current status again is a no-op and returns 200 with the same member.
Remove from the Roster
/v1/atlas/roster/{id}Permanently removes the invited person from this organization’s roster and returns 204 No Content.
Removal revokes the organization’s sharing grant and removes the active billing seat. It does not delete the person’s Sonar account or underlying health data. Repeating the same deletion returns 204.
API-created users use the Users API
These lifecycle routes reject API-created users with 409 api_user_lifecycle_managed_by_users_api. Use /v1/users/{id} for those users; deleting an API user has broader data-deletion effects.
Example
invitation = requests.post(
f"{BASE}/atlas/roster/invitations",
headers=HEADERS,
json={"email": "jordan@example.com", "full_name": "Jordan Kim"},
).json()const invitation = await fetch(`${base}/atlas/roster/invitations`, {
method: "POST",
headers,
body: JSON.stringify({ email: "jordan@example.com", full_name: "Jordan Kim" }),
}).then((response) => response.json());
Sonar