Members
Tags: data, members, users
A Member is a person in a workspace — a patient or plan member, or a staff member who works with them. These endpoints manage the member roster, the authenticated member's own profile, per-member custom fields, and bulk import and export.
In the product: Members
Resources
Request and response models used by the endpoints on this page.
BulkCreateMembersRequest
| Field | Type | Required | Description |
|---|---|---|---|
members | Array | ✓ | |
upsert | Boolean | If true, update existing members matched by externalId/email/phone (default: False) |
Example:
{
"members": [] // Array<BulkMemberItem>,
"upsert": false // Boolean, optional, default: False, If true, update existing members matched by externalId/email/phone
}
BulkCreateMembersResponse
| Field | Type | Required | Description |
|---|---|---|---|
errors | Array | ||
importedCount | Integer | ✓ | |
results | Array | ✓ | |
success | Boolean | ✓ | |
totalCount | Integer | ✓ |
Example:
{
"importedCount": 0 // Integer,
"totalCount": 0 // Integer,
"success": false // Boolean,
"results": [] // Array<BulkMemberResult>,
"errors": "string" // Array<String>, optional
}
BulkMemberItem
| Field | Type | Required | Description |
|---|---|---|---|
description | String | ||
email | String | ||
externalId | String | ||
labels | Array | ||
locale | String | ||
memberRoleId | Integer | ||
name | String | ||
notifyEmail | Boolean | ||
notifySms | Boolean | ||
notifyVoice | Boolean | ||
notifyWhatsapp | Boolean | ||
phone | String | ||
timezone | String |
Example:
{
"email": "string" // String, optional,
"phone": "string" // String, optional,
"name": "string" // String, optional,
"description": "string" // String, optional,
"externalId": "string" // String, optional,
"memberRoleId": 0 // Integer, optional,
"labels": "string" // Array<String>, optional,
"notifySms": false // Boolean, optional,
"notifyEmail": false // Boolean, optional,
"notifyVoice": false // Boolean, optional,
"notifyWhatsapp": false // Boolean, optional,
"locale": "string" // String, optional,
"timezone": "string" // String, optional
}
BulkMemberResult
| Field | Type | Required | Description |
|---|---|---|---|
error | String | ||
externalId | String | ||
index | Integer | ✓ | |
memberId | Integer | ||
status | Literal[created, updated, failed] | ✓ |
Example:
{
"index": 0 // Integer,
"status": null // Literal[created, updated, failed],
"memberId": 0 // Integer, optional,
"externalId": "string" // String, optional,
"error": "string" // String, optional
}
CapabilityRequirementFinding
| Field | Type | Required | Description |
|---|---|---|---|
kind | Literal[feature, member_scope] | ✓ | |
slug | String | ✓ | |
subject | Literal[org, workspace, member] | ✓ |
Example:
{
"kind": null // Literal[feature, member_scope],
"slug": "string" // String,
"subject": null // Literal[org, workspace, member]
}
CapabilityStatus
| Field | Type | Required | Description |
|---|---|---|---|
enabled | Boolean | ✓ | |
missing | Array | ✓ | |
slug | String | ✓ |
Example:
{
"slug": "string" // String,
"enabled": false // Boolean,
"missing": [] // Array<CapabilityRequirementFinding>
}
CreateWorkspaceMemberRequest
| Field | Type | Required | Description |
|---|---|---|---|
accountEnabled | Boolean | ||
accountTosAccepted | Boolean | ||
accountUuid | String | ||
dateOfBirth | Date | ||
description | String | ||
email | String | ||
emailTrusted | Boolean | ||
externalId | String | ||
isOrgOwner | Boolean | ||
labelIds | Array | ||
locale | String | ||
memberRoleId | Integer | ✓ | |
memberType | String | ||
name | String | ||
notifyEmail | Boolean | ||
notifySms | Boolean | ||
notifyVoice | Boolean | ||
notifyWhatsapp | Boolean | ||
ownerId | Integer | ||
phone | String | ||
phoneTrusted | Boolean | ||
timezone | String | ||
tosAccepted | Boolean |
Example:
{
"email": "string" // String, optional,
"phone": "string" // String, optional,
"accountUuid": "string" // String, optional,
"name": "string" // String, optional,
"description": "string" // String, optional,
"externalId": "string" // String, optional,
"dateOfBirth": "2024-01-01T00:00:00Z" // Date, optional,
"memberRoleId": 0 // Integer,
"notifySms": false // Boolean, optional,
"notifyEmail": false // Boolean, optional,
"notifyVoice": false // Boolean, optional,
"notifyWhatsapp": false // Boolean, optional,
"locale": "string" // String, optional,
"timezone": "string" // String, optional,
"labelIds": 0 // Array<Integer>, optional,
"memberType": "string" // String, optional,
"ownerId": 0 // Integer, optional,
"tosAccepted": false // Boolean, optional,
"emailTrusted": false // Boolean, optional,
"phoneTrusted": false // Boolean, optional,
"accountEnabled": false // Boolean, optional,
"isOrgOwner": false // Boolean, optional,
"accountTosAccepted": false // Boolean, optional
}
CurrentMemberResponse
| Field | Type | Required | Description |
|---|---|---|---|
accountEnabled | Boolean | ||
accountTosAccepted | Boolean | ✓ | |
accountUuid | String | ✓ | |
canLogin | Boolean | Default: True | |
capabilities | dict[str, CapabilityStatus] | Per-member surface-capability decisions. slug → {enabled, missing}. Each capability composes workspace feature availability with this member's scope authorization. See lib/capabilities/surfaces.py for CapabilityStatus and CapabilityRequirementFinding definitions. | |
createdAt | DateTime | ✓ | |
dateOfBirth | Date | ||
description | String | ✓ | |
email | String | ✓ | |
emailTrusted | Boolean | Default: False | |
experimentGroup | MemberExperimentGroupSummary | ||
externalId | String | ✓ | |
homeFolderId | Integer | ||
id | Integer | ✓ | |
isArchived | Boolean | Default: False | |
isOrgOwner | Boolean | ||
isSuperuser | Boolean | ||
labels | Array | Default: [] | |
locale | String | ✓ | |
memberRoleId | Integer | ✓ | |
memberRoleName | String | ✓ | |
memberType | String | Default: member | |
name | String | ✓ | |
notifyEmail | Boolean | ✓ | |
notifySms | Boolean | ✓ | |
notifyVoice | Boolean | ✓ | |
notifyWhatsapp | Boolean | Default: False | |
orgRole | String | ||
ownerId | Integer | ||
ownerName | String | ||
phone | String | ✓ | |
phoneTrusted | Boolean | Default: False | |
phoneType | String | ✓ | |
role | String | ✓ | |
scopes | Array | Default: [] | |
timezone | String | ||
tosAccepted | Boolean | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0 // Integer,
"uuid": "string" // String,
"role": "string" // String,
"tosAccepted": false // Boolean,
"accountTosAccepted": false // Boolean,
"accountUuid": "string" // String,
"createdAt": "2024-01-01T00:00:00Z" // DateTime,
"updatedAt": "2024-01-01T00:00:00Z" // DateTime,
"name": "string" // String,
"description": "string" // String,
"phone": "string" // String,
"phoneType": "string" // String,
"email": "string" // String,
"externalId": "string" // String,
"dateOfBirth": "2024-01-01T00:00:00Z" // Date, optional,
"emailTrusted": false // Boolean, optional, default: False,
"phoneTrusted": false // Boolean, optional, default: False,
"notifySms": false // Boolean,
"notifyEmail": false // Boolean,
"notifyVoice": false // Boolean,
"notifyWhatsapp": false // Boolean, optional, default: False,
"locale": "string" // String,
"memberRoleId": 0 // Integer,
"memberRoleName": "string" // String,
"homeFolderId": 0 // Integer, optional,
"labels": [] // Array<MemberLabelResponse>, optional, default: [],
"accountEnabled": false // Boolean, optional,
"isOrgOwner": false // Boolean, optional,
"isSuperuser": false // Boolean, optional,
"orgRole": "string" // String, optional,
"timezone": "string" // String, optional,
"memberType": "string" // String, optional, default: member,
"isArchived": false // Boolean, optional, default: False,
"ownerId": 0 // Integer, optional,
"ownerName": "string" // String, optional,
"canLogin": false // Boolean, optional, default: True,
"experimentGroup": null // MemberExperimentGroupSummary, optional,
"scopes": "string" // Array<String>, optional, default: [],
"capabilities": {} // dict[str, CapabilityStatus], optional, default: PydanticUndefined, Per-member surface-capability decisions. slug → {enabled, missing}. Each capability composes workspace feature availability with this member's scope authorization. See lib/capabilities/surfaces.py for CapabilityStatus and CapabilityRequirementFinding definitions.
}
DeleteMembershipResponse
| Field | Type | Required | Description |
|---|---|---|---|
message | String | ✓ |
Example:
{
"message": "string" // String
}
MemberCredentialResponse
| Field | Type | Required | Description |
|---|---|---|---|
appConnectionId | Integer | ||
appConnectionName | String | ||
connectedAt | String | ||
createdAt | String | ✓ | |
displayName | String | ||
emailVerified | Boolean | Default: False | |
externalEmail | String | ||
externalUserId | String | ||
externalUsername | String | ||
icon | String | ||
iconUrl | String | ||
id | Integer | ✓ | |
isDefault | Boolean | Default: False | |
lastUsedAt | String | ||
provider | String | ||
uuid | String |
Example:
{
"id": 0 // Integer,
"uuid": "string" // String, optional,
"displayName": "string" // String, optional,
"isDefault": false // Boolean, optional, default: False,
"provider": "string" // String, optional,
"externalUserId": "string" // String, optional,
"externalUsername": "string" // String, optional,
"externalEmail": "string" // String, optional,
"emailVerified": false // Boolean, optional, default: False,
"connectedAt": "string" // String, optional,
"lastUsedAt": "string" // String, optional,
"createdAt": "string" // String,
"appConnectionId": 0 // Integer, optional,
"appConnectionName": "string" // String, optional,
"icon": "string" // String, optional,
"iconUrl": "string" // String, optional
}
MemberFieldDefinitionListResponse
| Field | Type | Required | Description |
|---|---|---|---|
items | Array | ✓ |
Example:
{
"items": [] // Array<MemberFieldDefinitionResponse>
}
MemberFieldDefinitionResponse
| Field | Type | Required | Description |
|---|---|---|---|
key | String | ✓ | |
label | String | ✓ | |
serviceName | String | ||
serviceType | String |
Example:
{
"key": "string" // String,
"label": "string" // String,
"serviceName": "string" // String, optional,
"serviceType": "string" // String, optional
}
MemberFieldListResponse
| Field | Type | Required | Description |
|---|---|---|---|
items | Array | ✓ | |
total | Integer | ✓ |
Example:
{
"items": [] // Array<MemberFieldResponse>,
"total": 0 // Integer
}
MemberFieldResponse
| Field | Type | Required | Description |
|---|---|---|---|
createdAt | DateTime | ✓ | |
id | Integer | ✓ | |
key | String | ✓ | |
memberId | Integer | ✓ | |
serviceId | Integer | ✓ | |
serviceName | String | ✓ | |
serviceType | String | ✓ | |
updatedAt | DateTime | ✓ | |
value | String | ✓ |
Example:
{
"id": 0 // Integer,
"memberId": 0 // Integer,
"key": "string" // String,
"value": "string" // String,
"serviceId": 0 // Integer,
"serviceName": "string" // String,
"serviceType": "string" // String,
"createdAt": "2024-01-01T00:00:00Z" // DateTime,
"updatedAt": "2024-01-01T00:00:00Z" // DateTime
}
MemberImportPreviewResponse
| Field | Type | Required | Description |
|---|---|---|---|
rows | Array | ✓ | |
summary | MemberImportPreviewSummary | ✓ | |
total_rows | Integer | ✓ |
Example:
{
"total_rows": 0 // Integer,
"summary": null // MemberImportPreviewSummary,
"rows": [] // Array<MemberImportPreviewRow>
}
MemberImportPreviewRow
| Field | Type | Required | Description |
|---|---|---|---|
action | Literal[create, update, unchanged, conflict, error] | ✓ | |
conflict | MemberImportConflictInfo | ||
error | String | ||
existing_identity | MemberImportIdentitySnapshot | ||
incoming_identity | MemberImportIdentitySnapshot | ||
match | MemberImportMatchInfo | ||
proposed_changes | Array | Default: [] | |
row | Integer | ✓ |
Example:
{
"row": 0 // Integer,
"action": null // Literal[create, update, unchanged, conflict, error],
"match": null // MemberImportMatchInfo, optional,
"conflict": null // MemberImportConflictInfo, optional,
"existing_identity": null // MemberImportIdentitySnapshot, optional,
"incoming_identity": null // MemberImportIdentitySnapshot, optional,
"proposed_changes": "string" // Array<String>, optional, default: [],
"error": "string" // String, optional
}
MemberLabelResponse
| Field | Type | Required | Description |
|---|---|---|---|
color | String | ✓ | |
description | String | ✓ | |
id | Integer | ✓ | |
name | String | ✓ | |
slug | String | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0 // Integer,
"uuid": "string" // String,
"name": "string" // String,
"slug": "string" // String,
"color": "string" // String,
"description": "string" // String
}
SendPhoneConfirmationResponse
| Field | Type | Required | Description |
|---|---|---|---|
status | String | ✓ |
Example:
{
"status": "string" // String
}
UpdateWorkspaceMemberRequest
| Field | Type | Required | Description |
|---|---|---|---|
accountEnabled | Boolean | ||
accountTosAccepted | Boolean | ||
dateOfBirth | Date | ||
description | String | ||
email | String | ||
emailTrusted | Boolean | ||
externalId | String | ||
isOrgOwner | Boolean | ||
isSuperuser | Boolean | ||
labelIds | Array | ||
locale | String | ||
memberRoleId | Integer | ||
name | String | ||
notifyEmail | Boolean | ||
notifySms | Boolean | ||
notifyVoice | Boolean | ||
notifyWhatsapp | Boolean | ||
phone | String | ||
phoneTrusted | Boolean | ||
timezone | String | ||
tosAccepted | Boolean |
Example:
{
"tosAccepted": false // Boolean, optional,
"notifySms": false // Boolean, optional,
"notifyEmail": false // Boolean, optional,
"notifyVoice": false // Boolean, optional,
"notifyWhatsapp": false // Boolean, optional,
"memberRoleId": 0 // Integer, optional,
"locale": "string" // String, optional,
"timezone": "string" // String, optional,
"name": "string" // String, optional,
"description": "string" // String, optional,
"phone": "string" // String, optional,
"email": "string" // String, optional,
"externalId": "string" // String, optional,
"dateOfBirth": "2024-01-01T00:00:00Z" // Date, optional,
"labelIds": 0 // Array<Integer>, optional,
"emailTrusted": false // Boolean, optional,
"phoneTrusted": false // Boolean, optional,
"accountEnabled": false // Boolean, optional,
"isOrgOwner": false // Boolean, optional,
"accountTosAccepted": false // Boolean, optional,
"isSuperuser": false // Boolean, optional
}
WorkspaceMemberResponse
| Field | Type | Required | Description |
|---|---|---|---|
accountEnabled | Boolean | ||
accountTosAccepted | Boolean | ✓ | |
accountUuid | String | ✓ | |
canLogin | Boolean | Default: True | |
createdAt | DateTime | ✓ | |
dateOfBirth | Date | ||
description | String | ✓ | |
email | String | ✓ | |
emailTrusted | Boolean | Default: False | |
experimentGroup | MemberExperimentGroupSummary | ||
externalId | String | ✓ | |
homeFolderId | Integer | ||
id | Integer | ✓ | |
isArchived | Boolean | Default: False | |
isOrgOwner | Boolean | ||
isSuperuser | Boolean | ||
labels | Array | Default: [] | |
locale | String | ✓ | |
memberRoleId | Integer | ✓ | |
memberRoleName | String | ✓ | |
memberType | String | Default: member | |
name | String | ✓ | |
notifyEmail | Boolean | ✓ | |
notifySms | Boolean | ✓ | |
notifyVoice | Boolean | ✓ | |
notifyWhatsapp | Boolean | Default: False | |
orgRole | String | ||
ownerId | Integer | ||
ownerName | String | ||
phone | String | ✓ | |
phoneTrusted | Boolean | Default: False | |
phoneType | String | ✓ | |
role | String | ✓ | |
timezone | String | ||
tosAccepted | Boolean | ✓ | |
updatedAt | DateTime | ✓ | |
uuid | String | ✓ |
Example:
{
"id": 0 // Integer,
"uuid": "string" // String,
"role": "string" // String,
"tosAccepted": false // Boolean,
"accountTosAccepted": false // Boolean,
"accountUuid": "string" // String,
"createdAt": "2024-01-01T00:00:00Z" // DateTime,
"updatedAt": "2024-01-01T00:00:00Z" // DateTime,
"name": "string" // String,
"description": "string" // String,
"phone": "string" // String,
"phoneType": "string" // String,
"email": "string" // String,
"externalId": "string" // String,
"dateOfBirth": "2024-01-01T00:00:00Z" // Date, optional,
"emailTrusted": false // Boolean, optional, default: False,
"phoneTrusted": false // Boolean, optional, default: False,
"notifySms": false // Boolean,
"notifyEmail": false // Boolean,
"notifyVoice": false // Boolean,
"notifyWhatsapp": false // Boolean, optional, default: False,
"locale": "string" // String,
"memberRoleId": 0 // Integer,
"memberRoleName": "string" // String,
"homeFolderId": 0 // Integer, optional,
"labels": [] // Array<MemberLabelResponse>, optional, default: [],
"accountEnabled": false // Boolean, optional,
"isOrgOwner": false // Boolean, optional,
"isSuperuser": false // Boolean, optional,
"orgRole": "string" // String, optional,
"timezone": "string" // String, optional,
"memberType": "string" // String, optional, default: member,
"isArchived": false // Boolean, optional, default: False,
"ownerId": 0 // Integer, optional,
"ownerName": "string" // String, optional,
"canLogin": false // Boolean, optional, default: True,
"experimentGroup": null // MemberExperimentGroupSummary, optional
}
Endpoints
List & activity
GET /api/v2/w/{workspace_uuid}/members- MembersGET /api/v2/w/{workspace_uuid}/members/message-activity- Message Activity
Create & manage
POST /api/v2/w/{workspace_uuid}/members- MembersDELETE /api/v2/w/{workspace_uuid}/members/{member_id}- Delete MembersGET /api/v2/w/{workspace_uuid}/members/{member_id}- MembersPUT /api/v2/w/{workspace_uuid}/members/{member_id}- Update MembersPOST /api/v2/w/{workspace_uuid}/members/{member_id}/archive- ArchivePOST /api/v2/w/{workspace_uuid}/members/{member_id}/phone-confirmation- Phone ConfirmationPOST /api/v2/w/{workspace_uuid}/members/{member_id}/unarchive- Unarchive
Current member (me)
DELETE /api/v2/w/{workspace_uuid}/me- Delete MeGET /api/v2/w/{workspace_uuid}/me- MePUT /api/v2/w/{workspace_uuid}/me- Update MeGET /api/v2/w/{workspace_uuid}/me/credentials- CredentialsDELETE /api/v2/w/{workspace_uuid}/me/credentials/{credential_id}- Delete CredentialsGET /api/v2/w/{workspace_uuid}/members/owned- Owned
Custom fields
GET /api/v2/w/{workspace_uuid}/member-field-definitions- Member Field DefinitionsGET /api/v2/w/{workspace_uuid}/members/{member_id}/fields- FieldsPOST /api/v2/w/{workspace_uuid}/members/{member_id}/fields- FieldsDELETE /api/v2/w/{workspace_uuid}/members/{member_id}/fields/{field_id}- Delete FieldsPUT /api/v2/w/{workspace_uuid}/members/{member_id}/fields/{field_id}- Update Fields
Bulk operations
CSV import
POST /api/v2/w/{workspace_uuid}/members/import- ImportPOST /api/v2/w/{workspace_uuid}/members/import/preview- Preview
Export
List & activity
List and search the member roster, with message-activity summaries.
Members
GET /api/v2/w/{workspace_uuid}/members
Description:
List all workspace members with filtering and pagination.
Authorization: Requires members:read scope
Parameters:
workspace_uuid(String)memberFilterId(Integer)query(String)search(String)role(String)member_type(String)member_types(String)is_archived(Boolean)is_manager(Boolean)has_account(Boolean)exclude_ids(String)experimentId(Integer)experimentGroupId(Integer)experimentUnassigned(Boolean)page(Integer) — min: 1pageSize(Integer) — min: 1, max: 100sortBy(MemberSortField)sortOrder(SortOrder)
Response: See PaginatedResponse[WorkspaceMemberResponse]
Message Activity
GET /api/v2/w/{workspace_uuid}/members/message-activity
Description:
Get message activity (count per day) for specified members.
Authorization: Requires members:read scope
Parameters:
workspace_uuid(String)member_ids(String)days(Integer) — min: 1, max: 90
Create & manage
Create, fetch, update, archive, and delete Members.
Members
POST /api/v2/w/{workspace_uuid}/members
Description:
Create a new workspace member.
Authorization: Requires members:write scope
Parameters:
request- See CreateWorkspaceMemberRequest
Response: See WorkspaceMemberResponse
Delete Members
DELETE /api/v2/w/{workspace_uuid}/members/{member_id}
Description:
Permanently delete a workspace member and all their associated data.
Important: Members must be archived first before deletion. Use the archive endpoint to safely remove a member from the workspace. Permanent deletion is a destructive operation that cannot be undone.
The force flag allows workspace managers to auto-archive before deletion.
Without force, this endpoint is restricted to superusers for erasure scenarios.
Authorization: Requires members:admin scope
Parameters:
member_id(Integer)reassign_to_id(Integer)force(Boolean)
Response: See DeleteMembershipResponse
Members
GET /api/v2/w/{workspace_uuid}/members/{member_id}
Description:
Get a workspace member by ID.
Self-access: Users can view their own member profile. Admin access: MEMBERS_READ scope required for viewing other members.
Authentication: Requires workspace member
Parameters:
member_id(Integer)
Response: See WorkspaceMemberResponse
Update Members
PUT /api/v2/w/{workspace_uuid}/members/{member_id}
Description:
Update a workspace member.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)request- See UpdateWorkspaceMemberRequest
Response: See WorkspaceMemberResponse
Archive
POST /api/v2/w/{workspace_uuid}/members/{member_id}/archive
Description:
Archive a workspace member instead of deleting them.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)
Response: See WorkspaceMemberResponse
Phone Confirmation
POST /api/v2/w/{workspace_uuid}/members/{member_id}/phone-confirmation
Description:
Text a member asking them to confirm their phone (member-attested trust).
Authorization: Requires members:write scope
Parameters:
member_id(Integer)
Response: See SendPhoneConfirmationResponse
Unarchive
POST /api/v2/w/{workspace_uuid}/members/{member_id}/unarchive
Description:
Unarchive a previously archived workspace member.
For account-backed members this enforces the GLB membership invariant: the
GLB workspace_memberships link must exist or be recreatable (the account is
still in the workspace's org). When it isn't, unarchive_account_member_by_id
raises ConflictError -> HTTP 409 via the global handler and the member
stays archived.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)
Response: See WorkspaceMemberResponse
Current member (me)
The authenticated member's own profile, credentials, and owned members.
Delete Me
DELETE /api/v2/w/{workspace_uuid}/me
Description:
Leave a workspace.
Archives the workspace-level Member (so they no longer appear as active to others, while preserving assignments, chats, and audit history) and removes the account-to-workspace association so the user loses access.
Authentication: Requires workspace member
Response: See DeleteMembershipResponse
Me
GET /api/v2/w/{workspace_uuid}/me
Description:
Get the current user's workspace member profile.
This is a self-access endpoint - no special scope required. Includes the effective scopes and org role that the API honors for this user.
Authentication: Requires workspace member
Response: See CurrentMemberResponse
Update Me
PUT /api/v2/w/{workspace_uuid}/me
Description:
Update the current user's workspace member profile.
This is a self-access endpoint - no special scope required.
Authentication: Requires workspace member
Parameters:
request- See UpdateWorkspaceMemberRequest
Response: See WorkspaceMemberResponse
Credentials
GET /api/v2/w/{workspace_uuid}/me/credentials
Description:
Get the current member's connected integration credentials (Discord, etc.).
This is a self-access endpoint - no special scope required.
Authentication: Requires workspace member
Response: List of MemberCredentialResponse
Delete Credentials
DELETE /api/v2/w/{workspace_uuid}/me/credentials/{credential_id}
Description:
Delete/unlink a credential from the current member's account.
This is a self-access endpoint - no special scope required.
Authentication: Requires workspace member
Parameters:
credential_id(Integer)
Owned
GET /api/v2/w/{workspace_uuid}/members/owned
Description:
Get all members owned by the AUTHENTICATED member in this workspace.
IMPORTANT: This endpoint always uses the authenticated member (the one who logged in with their account), NOT the "acting-as" member. This is critical because:
- Only account-based members can own other members
- Owned members cannot own other members (prevents recursive ownership)
- The identity switcher needs to always show the same list regardless of which identity is currently active
Returns the authenticated member plus all non-archived MEMBER and AGENT-type records that have owner_id pointing to the authenticated member. This enables the identity switcher UI to show available identities (including personal agents) the user can switch between.
Use POST /members/switch to switch to an owned member identity.
Authorization: Requires members:read scope
Response: List of WorkspaceMemberResponse
Custom fields
Custom field definitions and per-member field values.
Member Field Definitions
GET /api/v2/w/{workspace_uuid}/member-field-definitions
Description:
Get available field definitions for this workspace.
Returns field keys and labels from active app connections' managed field definitions, plus any distinct user-created field keys.
Authorization: Requires members:read scope
Response: See MemberFieldDefinitionListResponse
Fields
GET /api/v2/w/{workspace_uuid}/members/{member_id}/fields
Description:
Get all fields for a member.
Returns all key-value fields associated with this member, including service-owned fields and placeholder entries for managed field definitions that don't have a value yet.
Authorization: Requires members:read scope
Parameters:
member_id(Integer)
Response: See MemberFieldListResponse
Fields
POST /api/v2/w/{workspace_uuid}/members/{member_id}/fields
Description:
Create a new field for a member.
When serviceId is provided, creates a managed field owned by that app connection. The key must match a managed field definition declared by the connection. Otherwise creates a user-owned field.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)request- See CreateMemberFieldRequest
Response: See MemberFieldResponse
Delete Fields
DELETE /api/v2/w/{workspace_uuid}/members/{member_id}/fields/{field_id}
Description:
Delete a member field.
Only user-created fields (service_id is null) can be deleted. Service-owned fields are read-only.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)field_id(Integer)
Update Fields
PUT /api/v2/w/{workspace_uuid}/members/{member_id}/fields/{field_id}
Description:
Update a member field value.
Both user-created and service-owned (managed) fields can have their values updated. The app connection owns the field's existence; the admin owns the value.
Authorization: Requires members:write scope
Parameters:
member_id(Integer)field_id(Integer)request- See UpdateMemberFieldRequest
Response: See MemberFieldResponse
Bulk operations
Bulk member operations.
Bulk
POST /api/v2/w/{workspace_uuid}/members/bulk
Description:
Bulk create or upsert workspace members.
Authorization: Requires members:write scope
Parameters:
request- See BulkCreateMembersRequest
Response: See BulkCreateMembersResponse
CSV import
Preview and run a CSV member import.
Import
POST /api/v2/w/{workspace_uuid}/members/import
Description:
Import members from CSV file with streaming progress updates.
identity_conflict_policy='overwrite_identity_fields' is intended to be
sent only after an operator reviews a preview. Two known, accepted limits:
- Preview→commit is not transactional (TOCTOU): the commit re-classifies each
row against live DB state, so under the default
skippolicy a row that became a conflict after the preview is still skipped. Underoverwritethe operator's prior approval is applied to current state, so an identity that changed between preview and commit is overwritten on the stale approval. Closing this would require optimistic locking / a preview token. - Preview-first is advisory, not enforced:
overwriterequires onlyMEMBERS_ADMIN(which can already mutate identity via the member-update API) and every overwrite is audited; there is no backend gate requiring a prior preview call.
Authorization: Requires members:admin scope
Parameters:
file(UploadFile)new_member_role_id(Integer)trust_email_addresses(Boolean)trust_phone_numbers(Boolean)identity_conflict_policy(IdentityConflictPolicy)
Preview
POST /api/v2/w/{workspace_uuid}/members/import/preview
Description:
Read-only preview classifying each CSV row before any write (GRA-5545).
Returns create/update/unchanged/conflict/error counts plus, for phone-only
identity conflicts, the existing vs incoming identity so the operator can
decide before committing. @phi_audit(bulk=True) because the response can
surface existing Member PHI in bulk; the response is never logged.
Design trade-off (accepted): returning existing name/date_of_birth for
conflicted rows lets one authorized call enumerate identity PHI for the
matched members. This is the explicit purpose of the conflict-review flow —
the operator must compare existing vs incoming to choose skip/overwrite — and
is bounded to phone-only conflict rows, gated by MEMBERS_ADMIN and the
bulk PHI audit above. Identity is not returned for create/update/unchanged
rows (PHI minimization).
Authorization: Requires members:admin scope
Parameters:
file(UploadFile)new_member_role_id(Integer)trust_email_addresses(Boolean)trust_phone_numbers(Boolean)
Response: See MemberImportPreviewResponse
Export
Export the member roster.
Export
POST /api/v2/w/{workspace_uuid}/members/export
Description:
Export members to CSV, matching the same filters the list view applies.
Authorization: Requires members:admin scope
Parameters:
selected_fields(Array) selected_data_types(Array) member_type(String)member_types(String)search(String)memberFilterId(Integer)query(String)role(String)