Skip to content

Groups and RBAC

Groups are the primary unit of access control in Arbitex. They collect users, define which AI models those users can reach, and carry per-group DLP detector overrides. All group management endpoints require the admin role and operate under the /api/admin/groups router prefix.


A group has a name (unique within the tenant), an optional description, and an optional link to an Azure Entra AD group via entra_ad_group_id. Groups are tenant-scoped — a group created in one tenant is not visible to another.

Each group stores:

FieldTypeNotes
idUUIDSystem-generated
namestring (255)Unique per tenant
descriptionstring (1000)Optional
entra_ad_group_idstring (255)Optional — maps to an Azure AD group for SCIM sync
created_attimestampSet on creation
updated_attimestampUpdated on any change

Arbitex has two platform-level roles:

RoleCapabilities
ADMINFull access to all admin endpoints including group CRUD, membership, model access, DLP config, and org-level defaults
USERNo access to admin endpoints; subject to group membership and model access rules

Group membership does not itself confer elevated role permissions. Roles are assigned directly to user accounts. Groups govern model access and DLP policy, not platform role.

Model access is resolved in this order:

  1. Org defaultsGET /api/admin/model-access/org-defaults — apply to all users in the organization.
  2. Group overridesGET /api/admin/groups/{group_id}/model-access — override org defaults for members of that group.
  3. Effective access — the result after applying applicable group rules on top of org defaults.

When a user belongs to multiple groups, the most permissive allow rule wins unless an explicit deny applies. Group rules always take precedence over org defaults when a rule exists for the model.


Terminal window
curl -X POST https://api.arbitex.ai/api/admin/groups \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "ml-engineers",
"description": "Machine learning engineering team",
"entra_ad_group_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}'

Request body:

FieldRequiredNotes
nameYesMust be unique within the tenant. Returns 409 if the name already exists.
descriptionNoFree-text description
entra_ad_group_idNoAzure AD object ID for SCIM group sync

Response:

{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"name": "ml-engineers",
"description": "Machine learning engineering team",
"entra_ad_group_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"created_at": "2026-03-09T00:00:00Z",
"updated_at": "2026-03-09T00:00:00Z"
}
Terminal window
curl https://api.arbitex.ai/api/admin/groups \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response:

{
"items": [
{
"id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
"name": "ml-engineers",
"description": "Machine learning engineering team",
"member_count": 12,
"entra_ad_group_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"created_at": "2026-03-09T00:00:00Z",
"updated_at": "2026-03-09T00:00:00Z"
}
],
"total": 1
}

The member_count field is included in both list and single-group responses.

Terminal window
curl https://api.arbitex.ai/api/admin/groups/{group_id} \
-H "Authorization: Bearer $ADMIN_TOKEN"

PUT performs a partial update — only fields provided in the body are changed.

Terminal window
curl -X PUT https://api.arbitex.ai/api/admin/groups/{group_id} \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated description for ML engineers"
}'

Any combination of name, description, and entra_ad_group_id may be included. Omitted fields are left unchanged.

Terminal window
curl -X DELETE https://api.arbitex.ai/api/admin/groups/{group_id} \
-H "Authorization: Bearer $ADMIN_TOKEN"

Deleting a group removes the group record, all membership associations, and all DLP config overrides for that group. Model access rules scoped to the group are also removed. This operation is not reversible.


Terminal window
curl https://api.arbitex.ai/api/admin/groups/{group_id}/members \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response includes user details for each member:

[
{
"id": "11111111-2222-3333-4444-555555555555",
"username": "alice",
"email": "alice@example.com"
}
]
Terminal window
curl -X POST https://api.arbitex.ai/api/admin/groups/{group_id}/members \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user_id": "11111111-2222-3333-4444-555555555555"
}'

The user_id must be a valid UUID string referencing an existing user. Returns 409 if the user is already a member of the group.

Terminal window
curl -X DELETE https://api.arbitex.ai/api/admin/groups/{group_id}/members/{user_id} \
-H "Authorization: Bearer $ADMIN_TOKEN"

Removing a user from a group takes effect immediately. The user’s effective model access reverts to org defaults for any models that were governed solely by the group rule.


Model access rules control which AI models the members of a group can use. Rules are set per group per model, and use an access_type of either allow or deny.

Terminal window
curl https://api.arbitex.ai/api/admin/groups/{group_id}/model-access \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response:

[
{
"model_id": "gpt-4o",
"provider": "openai",
"access_type": "allow"
},
{
"model_id": "claude-opus-4-6",
"provider": "anthropic",
"access_type": "deny"
}
]

This endpoint upserts — if a rule already exists for the given model_id, it is updated in place.

Terminal window
curl -X POST https://api.arbitex.ai/api/admin/groups/{group_id}/model-access \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_id": "gpt-4o",
"provider": "openai",
"access_type": "allow"
}'

Request body:

FieldRequiredNotes
model_idYesModel identifier string (e.g., gpt-4o)
providerYesProvider name (e.g., openai, anthropic)
access_typeYesallow or deny
Terminal window
curl -X DELETE https://api.arbitex.ai/api/admin/groups/{group_id}/model-access/{model_id} \
-H "Authorization: Bearer $ADMIN_TOKEN"

After removal, the org-level default for that model applies to group members.

Org defaults establish the baseline access for all users before group rules are applied.

Terminal window
curl https://api.arbitex.ai/api/admin/model-access/org-defaults \
-H "Authorization: Bearer $ADMIN_TOKEN"
Terminal window
curl -X POST https://api.arbitex.ai/api/admin/model-access/org-defaults \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model_id": "gpt-4o-mini",
"provider": "openai",
"access_type": "allow"
}'
Terminal window
curl -X DELETE https://api.arbitex.ai/api/admin/model-access/org-defaults/{model_id} \
-H "Authorization: Bearer $ADMIN_TOKEN"

The following matrix shows the effective access result for a given model, given an org-level default and a group-level override for a user who is a member of that group.

Org defaultGroup overrideEffective access
allowallowallow
allowdenydeny
allow(no rule)allow
denyallowallow
denydenydeny
deny(no rule)deny
(no rule)allowallow
(no rule)denydeny
(no rule)(no rule)deny (default-closed)

When no rule exists at either level, access is denied by default. To grant access to a model organization-wide, set an org-level allow default. To restrict a model for a specific group while it is allowed org-wide, set a group-level deny override for that group.


Each group can carry DLP detector overrides that change how detection events are handled for members of that group. These overrides apply in addition to the platform-level DLP policy.

ValueBehavior
SKIPBypass this detector entirely for the group — no detection is performed
BLOCKBlock the request when this detector fires
CANCELCancel the request and prompt the user to revise their input
REDACTRedact the matched content before the prompt is forwarded to the model
Terminal window
curl https://api.arbitex.ai/api/admin/groups/{group_id}/dlp \
-H "Authorization: Bearer $ADMIN_TOKEN"

Response:

[
{
"detector_name": "pii-ner",
"action": "REDACT",
"enabled": true
},
{
"detector_name": "secrets-regex",
"action": "BLOCK",
"enabled": true
}
]

PUT performs a full replacement of the group’s DLP config. The entire list is replaced — any detectors not included in the request body are removed from the group’s config.

Terminal window
curl -X PUT https://api.arbitex.ai/api/admin/groups/{group_id}/dlp \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '[
{
"detector_name": "pii-ner",
"action": "REDACT",
"enabled": true
},
{
"detector_name": "secrets-regex",
"action": "BLOCK",
"enabled": true
},
{
"detector_name": "financial-gliner",
"action": "SKIP",
"enabled": true
}
]'

To clear all DLP overrides for a group, PUT an empty array:

Terminal window
curl -X PUT https://api.arbitex.ai/api/admin/groups/{group_id}/dlp \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '[]'

Groups support an entra_ad_group_id field that maps the Arbitex group to an Azure Entra ID group object. This mapping is used by the SCIM provisioning connector to maintain membership automatically.

When SCIM sync is active, the connector pushes group membership changes from Entra ID to Arbitex. Adding or removing a user from the linked Entra AD group propagates to the Arbitex group membership without manual API calls.

The entra_ad_group_id can be set at group creation or updated via PUT:

Terminal window
# At creation
curl -X POST https://api.arbitex.ai/api/admin/groups \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "data-science",
"entra_ad_group_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}'
# Or added to an existing group
curl -X PUT https://api.arbitex.ai/api/admin/groups/{group_id} \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entra_ad_group_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}'

The entra_ad_group_id value is the Object ID of the group in Azure Entra ID, visible in the Azure Portal under Microsoft Entra IDGroups → the target group → Overview.

To unlink a group from Entra ID without deleting the group, set entra_ad_group_id to null:

Terminal window
curl -X PUT https://api.arbitex.ai/api/admin/groups/{group_id} \
-H "Authorization: Bearer $ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"entra_ad_group_id": null
}'

After unlinking, membership changes in Entra ID no longer propagate to this group. Existing memberships in Arbitex are not modified by the unlink operation.