openapi: 3.1.0 info: title: FastAPI contact: email: support@zenlytic.com version: 2.0.0 description: | ## Servers & Authentication ### Servers Zenlytic runs separate API hosts per region. Use the host matching where your organization is hosted. {% tabs %} {% tab title="US" %} **Base URL** `https://api-external.zenlytic.com/api/v2` {% endtab %} {% tab title="EU" %} **Base URL** `https://euapi-external.zenlytic.com/api/v2` {% endtab %} {% endtabs %} ### Authentication Include your personal access token as a bearer token in the `Authorization` header: ``` Authorization: Bearer YOUR_TOKEN ``` {% hint style="info" %} A token's scope — a single workspace (**Admin**) or your entire organization (**Org admin**) — is fixed when the token is created, based on your role in the workspace you created it from. It isn't visible from the token itself, so call `GET /me` to see what a given token can actually reach before building against it. See [Overview](README.md#discovering-your-tokens-scope) for the full scope table. {% endhint %} ## Getting Started {% stepper %} {% step %} ## Create a Personal Access Token See [Overview](README.md#creating-a-personal-access-token) for how to create one from your user menu. {% endstep %} {% step %} ## Check Your Token's Scope Call `GET /me` with your new token. It returns your organization and the workspaces the token can see — one workspace for an admin-scoped token, or every workspace in the organization for an org admin token. {% endstep %} {% step %} ## Make Your First Request Org admin token: call `GET /workspaces` to list every workspace in your organization. Admin token: call `GET /workspaces/{workspace_id}/groups` for a workspace your token can see. {% endstep %} {% endstepper %} ## Response Envelope Every response, success or error, is wrapped in the same `meta` envelope: ```json { "data": { ... }, "meta": { "status": "success", "errors": [], "warnings": [] } } ``` `meta.warnings` can carry non-fatal notices alongside a successful response — for example, two groups in a workspace sharing the same `user_attribute_precedence`. ## Error Responses Errors set `meta.status` to `"error"` and populate `meta.errors` with one entry per problem: ```json { "meta": { "status": "error", "errors": [ { "message": "Workspace not found", "status_code": 404, "error_code": "not_found", "occurred_at": "2026-08-05T12:00:00Z" } ], "warnings": [] } } ``` {% hint style="warning" %} `occurred_at`, `error_code`, and `error_metadata` are optional and may be `null` — key off `status_code` and `message` first. {% endhint %} | Code | Meaning | When it happens | | --- | --- | --- | | `400` | Bad Request | An application-level validation rule failed — not a schema/type error, but a business rule (e.g. a value out of range, an inferred setting with no valid value). | | `401` | Invalid token | The bearer token fails gateway-level verification — wrong issuer/key-id, wrong signing algorithm, bad signature, failed claims, or an empty subject. | | `403` | Forbidden | Any authentication or authorization failure — missing/invalid credential, a PAT used against a workspace outside its scope, insufficient permission, or a `workspace_id`/`group_id`/etc. that doesn't exist or isn't visible to this token. These deliberately share one generic message — the API does not reveal which case applies. | | `404` | Not Found | A specific named resource wasn't found within a scope you can otherwise access — distinct from the 403 case above, which covers the *scope itself* (e.g. the `workspace_id`) being inaccessible. Also returned for a request path that doesn't match any route. | | `405` | Method Not Allowed | Valid path, wrong HTTP verb (e.g. `PUT` on a route that only defines `GET`/`POST`). | | `409` | Conflict | Trying to create something that already exists in a way that would collide — a duplicate attribute-definition name in a workspace, an attribute already set on this group/member, or an existing group membership. | | `422` | Unprocessable Entity | The request itself doesn't match the expected shape — malformed JSON, a required field missing, or a field of the wrong type — caught by schema validation before any application logic runs. | | `429` | Too Many Requests | Rate limit exceeded. | | `500` | Internal Server Error | An unexpected, unhandled error. The message is always the same generic string — no internal detail is ever leaked to the client. | ## Rate Limiting The API enforces rate limits, keyed by your personal access token. Limits vary by endpoint, so don't assume a single number applies everywhere — check your current quota from the response headers instead of a fixed value from documentation: - `X-RateLimit-Limit` — your quota for the current window - `X-RateLimit-Remaining` — requests left in the current window - `X-RateLimit-Reset` — seconds until the window resets When a request is rejected, the API returns `429` with the standard error envelope: ```json { "meta": { "status": "error", "errors": [ { "message": "Rate limit exceeded", "status_code": 429 } ], "warnings": [] } } ``` {% hint style="info" %} On a `429`, back off exponentially and use `X-RateLimit-Reset` to know when it's safe to retry, rather than a fixed retry delay. {% endhint %} servers: - url: https://api-external.zenlytic.com/api/v2 description: US - url: https://euapi-external.zenlytic.com/api/v2 description: EU paths: /me: get: tags: - Me summary: Get Me description: |- Retrieve your own user ID, organization, and the workspaces you can see. {% hint style="info" %} Call this first when building against a new token. It tells you whether the token is scoped to a single workspace (**Admin**) or your whole organization (**Org admin**), which decides which endpoints below it can call. {% endhint %} operationId: get_me_me_get responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_MeSchema_' example: data: user_id: usr_111 organization: id: org_123 name: Acme Corp workspaces: - id: ws_456 name: acme-prod meta: status: success errors: [] warnings: [] 4XX: description: Client Error content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' 5XX: description: Server Error content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' security: - HTTPBearer: [] x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/me \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/me', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/me', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); /workspaces: get: tags: - Workspaces summary: List Workspaces description: |- List the workspaces in your organization. Archived workspaces are excluded unless ``include_archived`` is true. operationId: list_workspaces_for_organization_workspaces_get security: - HTTPBearer: [] parameters: - name: include_archived in: query required: false schema: type: boolean description: Include archived workspaces in the results. default: false title: Include Archived description: Include archived workspaces in the results. responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_WorkspaceSchema_' example: data: - id: ws_456 name: acme-prod provision_by_default: true meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Workspaces summary: Create Workspace description: |- Create a new workspace in your organization. Not a blank slate: the caller and every existing organization admin are auto-added as organization admins, so they'll immediately appear in the workspace's "All Users" group, whose membership always tracks the roster. Other org members aren't added until separately granted access. operationId: create_workspace_in_organization_workspaces_post security: - HTTPBearer: [] requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateWorkspaceSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_CreateWorkspaceResponseSchema_' example: data: id: ws_789 name: acme-staging provision_by_default: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"name": "acme-staging", "provision_by_default": false}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'name': 'acme-staging', 'provision_by_default': False} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"name": "acme-staging", "provision_by_default": false}), }); const data = await response.json(); /workspaces/{workspace_id}: delete: tags: - Workspaces summary: Archive Workspace description: |- Archive a workspace in your organization. Any user whose current workspace is the one being archived is silently reassigned to another workspace they belong to (or none, if they have no other workspace). {% hint style="danger" %} There is no confirmation step. Double-check `workspace_id` before calling — this is a soft delete, but the workspace's users are reassigned to another workspace in the organization immediately. {% endhint %} operationId: archive_workspace_for_organization_workspaces__workspace_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); /workspaces/{workspace_id}/groups: get: tags: - Groups summary: List Groups description: |- List every group in the workspace, including the built-in "All Users" group. Each group carries its member ids and its ``user_attribute_precedence``. A warning is returned when two groups in the workspace share a precedence value, since the winning user attribute is then undefined. operationId: get_groups_workspaces__workspace_id__groups_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_GroupResponseSchema_' example: data: - id: grp_123 workspace_id: ws_456 name: Sales is_all_users: false user_attribute_precedence: 1 users: - usr_111 - usr_222 meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//groups \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//groups', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Groups summary: Create Group description: |- Create a group in the workspace. ``user_attribute_precedence`` must be greater than 0 and decides which group's value wins when a member belongs to several groups that set the same user attribute. A warning is returned when the new group duplicates an existing precedence value. operationId: create_group_workspaces__workspace_id__groups_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateGroupSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_GroupResponseSchema_' example: data: id: grp_123 workspace_id: ws_456 name: Sales is_all_users: false user_attribute_precedence: 1 users: - usr_111 - usr_222 meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//groups \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"name": "Sales", "user_attribute_precedence": 1}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//groups', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'name': 'Sales', 'user_attribute_precedence': 1} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"name": "Sales", "user_attribute_precedence": 1}), }); const data = await response.json(); /workspaces/{workspace_id}/groups/{group_id}: get: tags: - Groups summary: Get Group description: |- Retrieve a single group in the workspace by id. Returns 404 if no group with that id exists in the workspace. operationId: get_group_workspaces__workspace_id__groups__group_id__get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_GroupResponseSchema_' example: data: id: grp_123 workspace_id: ws_456 name: Sales is_all_users: false user_attribute_precedence: 1 users: - usr_111 - usr_222 meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//groups/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//groups/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups/', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); patch: tags: - Groups summary: Update Group description: |- Update a group's name or user attribute precedence. Returns 400 if the group is the built-in "All Users" group, whose membership always tracks the workspace roster and can't be renamed or reweighted. A warning is returned if the update makes this group's precedence match another group's in the workspace. operationId: update_group_workspaces__workspace_id__groups__group_id__patch security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateGroupSchema' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_GroupResponseSchema_' example: data: id: grp_123 workspace_id: ws_456 name: Sales Team is_all_users: false user_attribute_precedence: 2 users: - usr_111 - usr_222 meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X PATCH https://api-external.zenlytic.com/api/v2/workspaces//groups/ \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"name": "Sales Team", "user_attribute_precedence": 2}' - lang: Python source: | import requests r = requests.patch( 'https://api-external.zenlytic.com/api/v2/workspaces//groups/', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'name': 'Sales Team', 'user_attribute_precedence': 2} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups/', { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"name": "Sales Team", "user_attribute_precedence": 2}), }); const data = await response.json(); delete: tags: - Groups summary: Delete Group description: |- Delete a group and the user attributes attached to it. Members are not deleted, only their membership. Returns 400 if the group is the built-in "All Users" group, whose membership always tracks the workspace roster and can't be deleted. operationId: delete_group_workspaces__workspace_id__groups__group_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces//groups/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces//groups/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); /workspaces/{workspace_id}/groups/{group_id}/members: get: tags: - Group Members summary: List Group Members description: |- List every member of the group. For the built-in "All Users" group, this returns every member of the workspace, since its membership always tracks the workspace roster. operationId: get_group_members_workspaces__workspace_id__groups__group_id__members_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_MemberSchema_' example: data: - id: usr_111 workspace_id: ws_456 role: admin first_name: Ada last_name: Lovelace email: ada@acme.com email_verified: true mfa_enabled: false identity_provider: Google meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//groups//members \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//members', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//members', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Group Members summary: Add Group Member description: |- Add a user to the group. Returns 404 if ``user_id`` is not already a member of the workspace. Returns 409 if the user is already in the group. Returns 400 if the group is the built-in "All Users" group, whose membership always tracks the workspace roster instead and can't be modified directly. operationId: add_group_member_workspaces__workspace_id__groups__group_id__members_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AddGroupMemberSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_GroupResponseSchema_' example: data: id: grp_123 workspace_id: ws_456 name: Sales is_all_users: false user_attribute_precedence: 1 users: - usr_111 - usr_222 meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//groups//members \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"user_id": "usr_111"}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//members', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'user_id': 'usr_111'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//members', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"user_id": "usr_111"}), }); const data = await response.json(); /workspaces/{workspace_id}/groups/{group_id}/members/{user_id}: delete: tags: - Group Members summary: Remove Group Member description: |- Remove a member from the group. Returns 404 if the user is not currently a member of the group. Returns 400 if the group is the built-in "All Users" group, whose membership always tracks the workspace roster instead and can't be modified directly. operationId: remove_group_member_workspaces__workspace_id__groups__group_id__members__user_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id - name: user_id in: path required: true schema: type: string title: User Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces//groups//members/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//members/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//members/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); /workspaces/{workspace_id}/members: get: tags: - Workspace Members summary: List Workspace Members description: List every member of the workspace. operationId: get_workspace_members_workspaces__workspace_id__members_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_MemberSchema_' example: data: - id: usr_111 workspace_id: ws_456 role: admin first_name: Ada last_name: Lovelace email: ada@acme.com email_verified: true mfa_enabled: false identity_provider: Google meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//members \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//members', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//members', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); /workspaces/{workspace_id}/invites: get: tags: - Invites summary: List Invites description: |- List every pending invite for the workspace. Invites that have already been accepted no longer appear here — they show up in ``GET /workspaces/{workspace_id}/members`` instead. operationId: list_invites_workspaces__workspace_id__invites_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_InviteSchema_' example: data: - id: invite_123 workspace_id: ws_456 email: ada@acme.com role: explore invite_url: https://app.zenlytic.com/join-workspace/invite_123?shopName=acme created_date: '2026-01-01T00:00:00Z' meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//invites \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//invites', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//invites', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Invites summary: Create Invite description: |- Invite a new member to the workspace by email. Reuses the same invite creation and email-send flow as the in-product "Invite" action. ``role`` is optional and defaults to the workspace's configured default role. Returns 409 if the email is already a member of the workspace or already has a pending invite. Returns 403 if ``role`` is ``organization_admin`` and the caller doesn't already hold organization-admin access on this workspace - only an existing organization admin can invite another one. On a free-tier workspace, ``role`` must be ``admin``; any other role returns 400. Returns 403 if the workspace is on a self-service plan and this invite would exceed its seat limit, its billing subscription isn't set up yet, or its subscription status doesn't currently allow billing changes (e.g. past due). Returns 400 if the workspace's SSO provider restricts allowed email domains and ``email``'s domain isn't one of them. operationId: create_invite_workspaces__workspace_id__invites_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateInviteSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_InviteSchema_' example: data: id: invite_123 workspace_id: ws_456 email: ada@acme.com role: explore invite_url: https://app.zenlytic.com/join-workspace/invite_123?shopName=acme created_date: '2026-01-01T00:00:00Z' meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//invites \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//invites', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//invites', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); /workspaces/{workspace_id}/user_attribute_definitions: get: tags: - Attribute Definitions summary: List Attribute Definitions description: |- List the user attribute definitions in the workspace. A definition declares the ``name``, ``label``, and ``data_type`` of an attribute. The per-user and per-group endpoints then assign values against these definitions. operationId: get_user_attribute_definitions_workspaces__workspace_id__user_attribute_definitions_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_UserAttributeDefinitionSchema_' example: data: - id: uad_123 workspace_id: ws_456 name: region data_type: string label: Region meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Attribute Definitions summary: Create Attribute Definition description: |- Create a user attribute definition in the workspace. Returns 409 if ``name`` is already used by another definition in the workspace. The ``data_type`` is fixed at creation time and cannot be changed afterwards. operationId: create_user_attribute_definition_workspaces__workspace_id__user_attribute_definitions_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUserAttributeDefinitionSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeDefinitionSchema_' example: data: id: uad_123 workspace_id: ws_456 name: region data_type: string label: Region meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"data_type": "string", "label": "Region", "name": "region"}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'data_type': 'string', 'label': 'Region', 'name': 'region'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"data_type": "string", "label": "Region", "name": "region"}), }); const data = await response.json(); /workspaces/{workspace_id}/user_attribute_definitions/{user_attribute_definition_id}: delete: tags: - Attribute Definitions summary: Delete Attribute Definition description: |- Delete a user attribute definition and every value assigned against it. This removes the attribute from all users and groups in the workspace. operationId: delete_user_attribute_definition_workspaces__workspace_id__user_attribute_definitions__user_attribute_definition_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_attribute_definition_id in: path required: true schema: type: string title: User Attribute Definition Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); patch: tags: - Attribute Definitions summary: Update Attribute Definition description: |- Update a user attribute definition's label. Only ``label`` is mutable — ``name`` and ``data_type`` are fixed once created, because assigned values and data model references depend on them. operationId: update_user_attribute_definition_workspaces__workspace_id__user_attribute_definitions__user_attribute_definition_id__patch security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_attribute_definition_id in: path required: true schema: type: string title: User Attribute Definition Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserAttributeDefinitionSchema' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeDefinitionSchema_' example: data: id: uad_123 workspace_id: ws_456 name: region data_type: string label: Sales Region meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X PATCH https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/ \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"label": "Sales Region"}' - lang: Python source: | import requests r = requests.patch( 'https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'label': 'Sales Region'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//user_attribute_definitions/', { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"label": "Sales Region"}), }); const data = await response.json(); /workspaces/{workspace_id}/groups/{group_id}/user_attributes: get: tags: - Group Attribute Values summary: List Group Attribute Values description: |- List the user attribute values set on a group. These apply to every user in the group. When a user is in several groups that set the same attribute, the group with the highest ``user_attribute_precedence`` wins. ``source`` is always ``"group"`` and ``source_id`` always matches this group's ID here — both only vary on the user attribute values endpoint, where a value can come from any of a user's groups or be set directly on the user. operationId: get_group_user_attributes_workspaces__workspace_id__groups__group_id__user_attributes_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_UserAttributeSchema_' example: data: - id: ua_789 user_attribute_definition_id: uad_123 value: west data_type: string name: region source: group source_id: grp_123 user_attribute_precedence: 1 is_overridden: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - Group Attribute Values summary: Create Group Attribute Value description: |- Set a user attribute value on a group. Returns 404 if ``user_attribute_definition_id`` doesn't reference an existing definition in the workspace. Returns 409 if the group already has a value set for that definition - patch the existing value instead. Returns 400 if ``value`` doesn't match the definition's ``data_type`` format: ``YYYY-MM-DD`` for ``date``, a numeric string for ``number``. operationId: create_group_user_attribute_workspaces__workspace_id__groups__group_id__user_attributes_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUserAttributeSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeSchema_' example: data: id: ua_789 user_attribute_definition_id: uad_123 value: west data_type: string name: region source: group source_id: grp_123 user_attribute_precedence: 1 is_overridden: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"user_attribute_definition_id": "uad_123", "value": "west"}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'user_attribute_definition_id': 'uad_123', 'value': 'west'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"user_attribute_definition_id": "uad_123", "value": "west"}), }); const data = await response.json(); /workspaces/{workspace_id}/groups/{group_id}/user_attributes/{user_attribute_id}: delete: tags: - Group Attribute Values summary: Delete Group Attribute Value description: |- Remove a user attribute value from a group. The definition itself is untouched — only this group's value for it is deleted. operationId: delete_group_user_attribute_workspaces__workspace_id__groups__group_id__user_attributes__user_attribute_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id - name: user_attribute_id in: path required: true schema: type: string title: User Attribute Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); patch: tags: - Group Attribute Values summary: Update Group Attribute Value description: |- Update the value of a user attribute already set on a group. Only ``value`` is mutable; to point at a different definition, delete this value and create a new one. Returns 400 if ``value`` doesn't match the existing definition's ``data_type`` format: ``YYYY-MM-DD`` for ``date``, a numeric string for ``number``. operationId: update_group_user_attribute_workspaces__workspace_id__groups__group_id__user_attributes__user_attribute_id__patch security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: group_id in: path required: true schema: type: string title: Group Id - name: user_attribute_id in: path required: true schema: type: string title: User Attribute Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserAttributeSchema' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeSchema_' example: data: id: ua_789 user_attribute_definition_id: uad_123 value: east data_type: string name: region source: group source_id: grp_123 user_attribute_precedence: 1 is_overridden: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X PATCH https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/ \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"value": "east"}' - lang: Python source: | import requests r = requests.patch( 'https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'value': 'east'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//groups//user_attributes/', { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"value": "east"}), }); const data = await response.json(); /workspaces/{workspace_id}/members/{user_id}/user_attributes: get: tags: - User Attribute Values summary: List User Attribute Values description: |- List the user attribute values that apply to a user. Includes values inherited from the user's groups as well as values set directly on the user. ``is_overridden`` marks a group-inherited value that a higher-precedence group's value, or a value set directly on the user, has superseded - so the effective set is the entries where it is false. ``user_attribute_precedence`` is ``null`` exactly when ``source`` is ``"user"`` (a directly-set value) - only groups carry a precedence. operationId: get_member_user_attributes_workspaces__workspace_id__members__user_id__user_attributes_get security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_id in: path required: true schema: type: string title: User Id responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2CollectionResponse_UserAttributeSchema_' example: data: - id: ua_789 user_attribute_definition_id: uad_123 value: west data_type: string name: region source: user source_id: usr_111 is_overridden: false - id: ua_790 user_attribute_definition_id: uad_124 value: '2024-01-15' data_type: date name: renewal_date source: group source_id: grp_123 user_attribute_precedence: 1 is_overridden: true meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests r = requests.get( 'https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes', { headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); const data = await response.json(); post: tags: - User Attribute Values summary: Create User Attribute Value description: |- Set a user attribute value directly on a user. A value set here takes precedence over any value the user inherits from a group. Returns 404 if ``user_attribute_definition_id`` doesn't reference an existing definition in the workspace. Returns 409 if the user already has a value set for that definition - patch the existing value instead. Returns 400 if ``value`` doesn't match the definition's ``data_type`` format: ``YYYY-MM-DD`` for ``date``, a numeric string for ``number``. operationId: create_member_user_attribute_workspaces__workspace_id__members__user_id__user_attributes_post security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_id in: path required: true schema: type: string title: User Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CreateUserAttributeSchema' responses: '201': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeSchema_' example: data: id: ua_789 user_attribute_definition_id: uad_123 value: west data_type: string name: region source: user source_id: usr_111 is_overridden: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X POST https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"user_attribute_definition_id": "uad_123", "value": "west"}' - lang: Python source: | import requests r = requests.post( 'https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'user_attribute_definition_id': 'uad_123', 'value': 'west'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes', { method: 'POST', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"user_attribute_definition_id": "uad_123", "value": "west"}), }); const data = await response.json(); /workspaces/{workspace_id}/members/{user_id}/user_attributes/{user_attribute_id}: delete: tags: - User Attribute Values summary: Delete User Attribute Value description: |- Remove a user attribute value set directly on a user. Only values set on the user can be deleted here; group-inherited values are managed on the group. Once removed, any group value for that definition applies again. operationId: delete_member_user_attribute_workspaces__workspace_id__members__user_id__user_attributes__user_attribute_id__delete security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_id in: path required: true schema: type: string title: User Id - name: user_attribute_id in: path required: true schema: type: string title: User Attribute Id responses: '204': description: Successful Response 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X DELETE https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/ \ -H 'Authorization: Bearer YOUR_TOKEN' - lang: Python source: | import requests requests.delete( 'https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/', headers={'Authorization': 'Bearer YOUR_TOKEN'} ) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/', { method: 'DELETE', headers: { 'Authorization': 'Bearer YOUR_TOKEN' }, }); patch: tags: - User Attribute Values summary: Update User Attribute Value description: |- Update the value of a user attribute set directly on a user. Only ``value`` is mutable; to point at a different definition, delete this value and create a new one. Returns 400 if ``value`` doesn't match the existing definition's ``data_type`` format: ``YYYY-MM-DD`` for ``date``, a numeric string for ``number``. operationId: update_member_user_attribute_workspaces__workspace_id__members__user_id__user_attributes__user_attribute_id__patch security: - HTTPBearer: [] parameters: - name: workspace_id in: path required: true schema: type: string title: Workspace Id - name: user_id in: path required: true schema: type: string title: User Id - name: user_attribute_id in: path required: true schema: type: string title: User Attribute Id requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/UpdateUserAttributeSchema' responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/ApiV2Response_UserAttributeSchema_' example: data: id: ua_789 user_attribute_definition_id: uad_123 value: east data_type: string name: region source: user source_id: usr_111 is_overridden: false meta: status: success errors: [] warnings: [] 4XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Client Error 5XX: content: application/json: schema: $ref: '#/components/schemas/ApiV2ErrorResponse' description: Server Error x-codeSamples: - lang: cURL source: | curl -L -X PATCH https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/ \ -H 'Authorization: Bearer YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"value": "east"}' - lang: Python source: | import requests r = requests.patch( 'https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/', headers={'Authorization': 'Bearer YOUR_TOKEN'}, json={'value': 'east'} ) print(r.json()) - lang: JavaScript source: | const response = await fetch('https://api-external.zenlytic.com/api/v2/workspaces//members//user_attributes/', { method: 'PATCH', headers: { 'Authorization': 'Bearer YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({"value": "east"}), }); const data = await response.json(); components: schemas: AddGroupMemberSchema: properties: user_id: type: string title: User Id type: object required: - user_id title: AddGroupMemberSchema examples: - user_id: usr_111 ApiV2CollectionResponse_GroupResponseSchema_: properties: data: items: $ref: '#/components/schemas/GroupResponseSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[GroupResponseSchema] ApiV2CollectionResponse_InviteSchema_: properties: data: items: $ref: '#/components/schemas/InviteSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[InviteSchema] ApiV2CollectionResponse_MemberSchema_: properties: data: items: $ref: '#/components/schemas/MemberSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[MemberSchema] ApiV2CollectionResponse_UserAttributeDefinitionSchema_: properties: data: items: $ref: '#/components/schemas/UserAttributeDefinitionSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[UserAttributeDefinitionSchema] ApiV2CollectionResponse_UserAttributeSchema_: properties: data: items: $ref: '#/components/schemas/UserAttributeSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[UserAttributeSchema] ApiV2CollectionResponse_WorkspaceSchema_: properties: data: items: $ref: '#/components/schemas/WorkspaceSchema' type: array title: Data meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2CollectionResponse[WorkspaceSchema] ApiV2ErrorResponse: properties: meta: $ref: '#/components/schemas/MetaSchema' type: object required: - meta title: ApiV2ErrorResponse ApiV2Response_CreateWorkspaceResponseSchema_: properties: data: $ref: '#/components/schemas/CreateWorkspaceResponseSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[CreateWorkspaceResponseSchema] ApiV2Response_GroupResponseSchema_: properties: data: $ref: '#/components/schemas/GroupResponseSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[GroupResponseSchema] ApiV2Response_InviteSchema_: properties: data: $ref: '#/components/schemas/InviteSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[InviteSchema] ApiV2Response_MeSchema_: properties: data: $ref: '#/components/schemas/MeSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[MeSchema] ApiV2Response_UserAttributeDefinitionSchema_: properties: data: $ref: '#/components/schemas/UserAttributeDefinitionSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[UserAttributeDefinitionSchema] ApiV2Response_UserAttributeSchema_: properties: data: $ref: '#/components/schemas/UserAttributeSchema' meta: $ref: '#/components/schemas/MetaSchema' type: object required: - data - meta title: ApiV2Response[UserAttributeSchema] BaseErrorMetadata: properties: {} type: object title: BaseErrorMetadata CreateGroupSchema: properties: name: type: string title: Name user_attribute_precedence: type: integer title: User Attribute Precedence description: Must be greater than 0; 0 is reserved for the all_users group. type: object required: - name - user_attribute_precedence title: CreateGroupSchema examples: - name: Sales user_attribute_precedence: 1 CreateInviteSchema: properties: email: type: string title: Email role: anyOf: - type: string enum: - organization_admin - admin - develop - develop_without_deploy - explore - view - restricted - embed - embedded_with_scheduling - embed_with_sql - type: 'null' title: Role description: The role to grant once the invite is accepted; defaults to the workspace's configured default role if omitted. type: object required: - email title: CreateInviteSchema CreateUserAttributeDefinitionSchema: properties: name: type: string title: Name description: A stable, unique key for this definition within the workspace, referenced by the data model - unlike `label`, it can't be changed after creation. data_type: $ref: '#/components/schemas/UserAttributeDataType' description: 'Determines the format required in `value` wherever this definition is used: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' label: type: string title: Label description: The human-facing display text for this definition; unlike `name`, this can be changed at any time. type: object required: - name - data_type - label title: CreateUserAttributeDefinitionSchema examples: - data_type: string label: Region name: region CreateUserAttributeSchema: properties: user_attribute_definition_id: type: string title: User Attribute Definition Id description: ID of an existing definition in this workspace - see `GET .../user_attribute_definitions`. value: type: string title: Value description: 'Must match the referenced definition''s `data_type` format: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' type: object required: - user_attribute_definition_id - value title: CreateUserAttributeSchema examples: - user_attribute_definition_id: uad_123 value: west CreateWorkspaceResponseSchema: properties: id: type: string title: Id name: type: string title: Name provision_by_default: type: boolean title: Provision By Default description: When true, new users signing in via SSO are automatically granted access to this workspace; when false, they need an explicit invite. type: object required: - id - name - provision_by_default title: CreateWorkspaceResponseSchema examples: - id: ws_789 name: acme-staging provision_by_default: false CreateWorkspaceSchema: properties: name: type: string title: Name provision_by_default: type: boolean title: Provision By Default description: When true, new users signing in via SSO are automatically granted access to this workspace; when false, they need an explicit invite. default: false type: object required: - name title: CreateWorkspaceSchema examples: - name: acme-staging provision_by_default: false ErrorSchema: properties: message: type: string title: Message status_code: anyOf: - type: integer - type: 'null' title: Status Code description: Matches this response's actual HTTP status code. occurred_at: anyOf: - type: string - type: 'null' title: Occurred At description: ISO 8601 UTC timestamp. error_code: anyOf: - type: string - type: 'null' title: Error Code description: Machine-readable code for errors that need special handling (e.g. "SSO_REQUIRED") rather than being shown generically; null for most errors. error_metadata: anyOf: - $ref: '#/components/schemas/BaseErrorMetadata' - type: 'null' description: Additional structured detail for specific error conditions; usually null. type: object required: - message title: ErrorSchema examples: - message: Workspace not found occurred_at: '2026-08-05T12:00:00Z' status_code: 404 GroupResponseSchema: properties: id: type: string title: Id workspace_id: type: string title: Workspace Id name: type: string title: Name is_all_users: type: boolean title: Is All Users description: Whether this is the built-in group containing every workspace member; its membership always tracks the roster and can't be edited directly. user_attribute_precedence: type: integer title: User Attribute Precedence description: Determines which group's value wins when a member is in several groups that set the same user attribute; higher wins. users: items: type: string type: array title: Users description: IDs of the group's members. type: object required: - id - workspace_id - name - is_all_users - user_attribute_precedence - users title: GroupResponseSchema examples: - id: grp_123 is_all_users: false name: Sales user_attribute_precedence: 1 users: - usr_111 - usr_222 workspace_id: ws_456 InferredProviderType: type: string enum: - Okta - Entra - Google - Email - Unknown title: InferredProviderType InviteSchema: properties: id: type: string title: Id workspace_id: type: string title: Workspace Id email: type: string title: Email role: type: string enum: - organization_admin - admin - develop - develop_without_deploy - explore - view - restricted - embed - embedded_with_scheduling - embed_with_sql title: Role description: The role this invite will grant once accepted. invite_url: type: string title: Invite Url description: The signup link for the invitee to accept this invite; the same link sent in the invite email. created_date: type: string format: date-time title: Created Date type: object required: - id - workspace_id - email - role - invite_url - created_date title: InviteSchema examples: - created_date: '2026-01-01T00:00:00Z' email: ada@acme.com id: invite_123 invite_url: https://app.zenlytic.com/join-workspace/invite_123?shopName=acme role: explore workspace_id: ws_456 MeSchema: properties: user_id: type: string title: User Id organization: $ref: '#/components/schemas/MyOrganizationSchema' workspaces: items: $ref: '#/components/schemas/MyWorkspaceSchema' type: array title: Workspaces description: Workspaces in your organization that you're a member of and, for a PAT scoped to specific workspaces, within the token's scope. Archived workspaces are excluded. type: object required: - user_id - organization - workspaces title: MeSchema examples: - organization: id: org_123 name: Acme Corp user_id: usr_111 workspaces: - id: ws_456 name: acme-prod MemberSchema: properties: id: type: string title: Id workspace_id: type: string title: Workspace Id role: type: string enum: - organization_admin - admin - develop - develop_without_deploy - explore - view - restricted - embed - embedded_with_scheduling - embed_with_sql title: Role description: The member's access level in this workspace. external_user_id: anyOf: - type: string - type: 'null' title: External User Id description: The member's ID in an embedding customer's own system, set when this member was provisioned through the embedded-analytics token flow; null otherwise. first_name: anyOf: - type: string - type: 'null' title: First Name last_name: anyOf: - type: string - type: 'null' title: Last Name email: type: string title: Email email_verified: type: boolean title: Email Verified mfa_enabled: type: boolean title: Mfa Enabled identity_provider: $ref: '#/components/schemas/InferredProviderType' description: The identity provider the member's account was created with. type: object required: - id - workspace_id - role - external_user_id - first_name - last_name - email - email_verified - mfa_enabled - identity_provider title: MemberSchema examples: - email: ada@acme.com email_verified: true first_name: Ada id: usr_111 identity_provider: Google last_name: Lovelace mfa_enabled: false role: admin workspace_id: ws_456 MetaSchema: properties: status: $ref: '#/components/schemas/ResponseStatus' errors: items: $ref: '#/components/schemas/ErrorSchema' type: array title: Errors description: Non-empty exactly when `status` is "error". warnings: items: $ref: '#/components/schemas/WarningSchema' type: array title: Warnings description: Can be non-empty even when `status` is "success" - a non-fatal issue with an otherwise-successful request. type: object required: - status title: MetaSchema examples: - errors: [] status: success warnings: [] MyOrganizationSchema: properties: id: type: string title: Id name: type: string title: Name type: object required: - id - name title: MyOrganizationSchema examples: - id: org_123 name: Acme Corp MyWorkspaceSchema: properties: id: type: string title: Id name: type: string title: Name type: object required: - id - name title: MyWorkspaceSchema examples: - id: ws_456 name: acme-prod ResponseStatus: type: string enum: - success - error title: ResponseStatus UpdateGroupSchema: properties: name: anyOf: - type: string - type: 'null' title: Name user_attribute_precedence: anyOf: - type: integer - type: 'null' title: User Attribute Precedence description: Must be greater than 0; 0 is reserved for the all_users group. type: object title: UpdateGroupSchema examples: - name: Sales Team user_attribute_precedence: 2 UpdateUserAttributeDefinitionSchema: properties: label: type: string title: Label description: The human-facing display text for this definition; unlike `name`, this can be changed at any time. type: object required: - label title: UpdateUserAttributeDefinitionSchema examples: - label: Sales Region UpdateUserAttributeSchema: properties: value: type: string title: Value description: 'Must match the existing definition''s `data_type` format: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' type: object required: - value title: UpdateUserAttributeSchema examples: - value: east UserAttributeDataType: type: string enum: - string - number - date title: UserAttributeDataType UserAttributeDefinitionSchema: properties: id: type: string title: Id workspace_id: type: string title: Workspace Id name: type: string title: Name description: A stable, unique key for this definition within the workspace, referenced by the data model - unlike `label`, it can't be changed after creation. data_type: $ref: '#/components/schemas/UserAttributeDataType' description: 'Determines the format required in `value` wherever this definition is used: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' label: type: string title: Label description: The human-facing display text for this definition; unlike `name`, this can be changed at any time. type: object required: - id - workspace_id - name - data_type - label title: UserAttributeDefinitionSchema examples: - data_type: string id: uad_123 label: Region name: region workspace_id: ws_456 UserAttributeSchema: properties: id: type: string title: Id user_attribute_definition_id: type: string title: User Attribute Definition Id description: ID of the definition this value is set against - see `GET .../user_attribute_definitions`. value: type: string title: Value description: 'Formatted per `data_type`: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' data_type: $ref: '#/components/schemas/UserAttributeDataType' description: 'Determines `value`''s format: "string" allows free text, "number" requires a parseable number, "date" requires `YYYY-MM-DD`.' name: type: string title: Name description: The referenced `user_attribute_definition_id`'s `name`. source: $ref: '#/components/schemas/UserAttributeSource' description: Whether this value is set directly on the user ("user") or inherited from a group ("group"). source_id: type: string title: Source Id description: ID of the group or user (matching `source`) this value comes from. user_attribute_precedence: anyOf: - type: integer - type: 'null' title: User Attribute Precedence description: The source group's precedence; null when `source` is "user" - only groups carry a precedence. is_overridden: type: boolean title: Is Overridden description: True if a higher-precedence group value, or a directly-set user value, takes effect instead of this one. type: object required: - id - user_attribute_definition_id - value - data_type - name - source - source_id - user_attribute_precedence - is_overridden title: UserAttributeSchema examples: - data_type: string id: ua_789 is_overridden: false name: region source: group source_id: grp_123 user_attribute_definition_id: uad_123 user_attribute_precedence: 1 value: west UserAttributeSource: type: string enum: - user - group title: UserAttributeSource WarningSchema: properties: message: type: string title: Message type: object required: - message title: WarningSchema examples: - message: 3 rows were skipped due to invalid formatting WorkspaceSchema: properties: id: type: string title: Id name: type: string title: Name provision_by_default: type: boolean title: Provision By Default description: When true, new users signing in via SSO are automatically granted access to this workspace; when false, they need an explicit invite. archived_at: anyOf: - type: string format: date-time - type: 'null' title: Archived At description: When this workspace was archived; null while active. type: object required: - id - name - provision_by_default title: WorkspaceSchema examples: - id: ws_456 name: acme-prod provision_by_default: true securitySchemes: HTTPBearer: type: http description: A Personal Access Token (PAT). scheme: bearer tags: - name: Organization Administration x-page-title: Organization Administration x-page-icon: building x-page-description: Organization-wide administration, spanning every workspace you belong to. Requires the Organization Admin role. - name: Workspace Administration x-page-title: Workspace Administration x-page-icon: user-shield x-page-description: Administration scoped to a single workspace. Requires the Admin role. - name: Me x-page-title: Me x-page-icon: id-card x-page-description: Your own user ID, organization, and workspace access. - name: Workspaces x-parent: Organization Administration x-page-title: Workspaces x-page-icon: layer-group x-page-description: Create, list, and archive workspaces in your organization. - name: Invites x-parent: Workspace Administration x-page-title: Invites x-page-icon: envelope x-page-description: Invite new members to a workspace and view pending invites. - name: Attribute Definitions x-parent: Workspace Administration x-page-title: Attribute Definitions x-page-icon: sliders x-page-description: Define the custom attributes available to groups and users. - name: Group Attribute Values x-parent: Groups x-page-title: Group Attribute Values x-page-icon: tags x-page-description: Set and manage user attribute values on a group. - name: User Attribute Values x-parent: Workspace Members x-page-title: User Attribute Values x-page-icon: user-tag x-page-description: Set and manage user attribute values on a user. - name: Workspace Members x-parent: Workspace Administration x-page-title: Workspace Members x-page-icon: user x-page-description: List a workspace's members. - name: Groups x-parent: Workspace Administration x-page-title: Groups x-page-icon: users x-page-description: Manage groups. - name: Group Members x-parent: Groups x-page-title: Group Members x-page-icon: user-group x-page-description: Add, remove, and list the members of a group.