Admin - Roles

Manage tenant roles and permissions through the Admin API. Create custom roles with fine-grained permission sets, assign credit limits, compare permissions across roles, and browse the permissions catalog.

List Roles

List all roles visible to the caller. When tenant_id is provided, returns default tenant roles plus custom roles scoped to that tenant. When omitted, returns all custom roles for the caller's MSP.

Endpoint

GET /v1/admin/roles

Query Parameters

  • tenant_id (optional): Tenant HashID — filter to roles assignable to this tenant
  • limit (optional): Maximum number of roles to return per source (1-100, default: 10)
  • offset (optional): Number of roles to skip per source (default: 0)

Example Query

curl 'https://ai.hatz.ai/v1/admin/roles?tenant_id=tenant_abc123&limit=20&offset=0' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response

{
  "roles": [
    {
      "id": "role_a3k9x2m8",
      "name": "general_user",
      "display_name": "General User",
      "description": "Standard user access",
      "user_credit_limit": null,
      "role_source": "default",
      "scope": null,
      "permissions_count": 12,
      "permissions_preview": ["Secure Chat", "App Builder", "Workshop Access"],
      "assigned_users_count": 45
    },
    {
      "id": "role_b7j2y5p1",
      "name": "engineering-lead",
      "display_name": "Engineering Lead",
      "description": "Custom role for engineering team leads",
      "user_credit_limit": 5000.0,
      "role_source": "custom",
      "scope": "tenant",
      "permissions_count": 18,
      "permissions_preview": ["Secure Chat", "App Builder", "Workflow Management"],
      "assigned_users_count": 3
    }
  ],
  "total_count": 2
}

Get Role Detail

Get full detail for a role (custom or default) including its permissions.

Endpoint

GET /v1/admin/roles/{role_id}

Path Parameters

  • role_id (required): Role HashID (e.g., "role_a3k9x2m8")

Example Query

curl 'https://ai.hatz.ai/v1/admin/roles/role_a3k9x2m8' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response

{
  "id": "role_a3k9x2m8",
  "name": "general_user",
  "display_name": "General User",
  "description": "Standard user access",
  "user_credit_limit": null,
  "role_source": "default",
  "scope": null,
  "permissions_count": 3,
  "permissions_preview": ["Secure Chat", "App Builder", "Workshop Access"],
  "assigned_users_count": 45,
  "permissions": [
    {
      "name": "secure_chat",
      "printable_name": "Secure Chat",
      "description": "Access to the secure AI chat",
      "scope": "entity",
      "tags": ["chat"],
      "user_selectable": true
    },
    {
      "name": "app_builder",
      "printable_name": "App Builder",
      "description": "Create and manage apps",
      "scope": "entity",
      "tags": ["apps"],
      "user_selectable": true
    },
    {
      "name": "workshop_access",
      "printable_name": "Workshop Access",
      "description": "View and use existing apps in the workshop",
      "scope": "entity",
      "tags": ["apps"],
      "user_selectable": true
    }
  ]
}

Get Role Permissions

List permissions assigned to a specific role with pagination.

Endpoint

GET /v1/admin/roles/{role_id}/permissions

Path Parameters

  • role_id (required): Role HashID (e.g., "role_a3k9x2m8")

Query Parameters

  • limit (optional): Maximum number of permissions to return (1-200, default: 10)
  • offset (optional): Number of permissions to skip (default: 0)

Example Query

curl 'https://ai.hatz.ai/v1/admin/roles/role_a3k9x2m8/permissions?limit=50&offset=0' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response

{
  "permissions": [
    {
      "name": "secure_chat",
      "printable_name": "Secure Chat",
      "description": "Access to the secure AI chat",
      "scope": "entity",
      "tags": ["chat"],
      "user_selectable": true
    }
  ],
  "total_count": 12
}

Compare Role Permissions

Compare permissions across multiple roles side-by-side. Useful for auditing differences between roles.

Endpoint

POST /v1/admin/roles/compare-permissions

Request Body

  • role_ids (required): List of role HashIDs to compare (max 10)
{
  "role_ids": ["role_a3k9x2m8", "role_b7j2y5p1"]
}

Example Request

curl -X POST 'https://ai.hatz.ai/v1/admin/roles/compare-permissions' \
  -H 'X-API-Key: $HATZ_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "role_ids": ["role_a3k9x2m8", "role_b7j2y5p1"]
  }'

Response

{
  "permissions": [
    {
      "permission_name": "secure_chat",
      "printable_name": "Secure Chat",
      "role_a3k9x2m8": true,
      "role_b7j2y5p1": true
    },
    {
      "permission_name": "workflow_management",
      "printable_name": "Workflow Management",
      "role_a3k9x2m8": false,
      "role_b7j2y5p1": true
    }
  ],
  "role_summaries": [
    {
      "id": "role_a3k9x2m8",
      "name": "general_user",
      "display_name": "General User",
      "permissions_count": 12
    },
    {
      "id": "role_b7j2y5p1",
      "name": "engineering-lead",
      "display_name": "Engineering Lead",
      "permissions_count": 18
    }
  ]
}

Create Custom Role

Create a new custom role. When tenant_id is provided the role is scoped to that tenant. When omitted the role is MSP-wide.

Endpoint

POST /v1/admin/roles/custom

Request Body

  • display_name (required): Human-readable name shown in the UI
  • description (optional): Role description
  • user_credit_limit (optional): Per-user credit limit
  • tenant_id (optional): Tenant HashID — scopes the role to that tenant; omit for MSP-wide
  • permission_names (optional): List of permission slugs to assign to the new role
{
  "display_name": "string",
  "description": "string",
  "user_credit_limit": 5000.0,
  "tenant_id": "string",
  "permission_names": ["secure_chat", "app_builder"]
}

Example Request

curl -X POST 'https://ai.hatz.ai/v1/admin/roles/custom' \
  -H 'X-API-Key: $HATZ_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "display_name": "Engineering Lead",
    "description": "Custom role for engineering team leads",
    "user_credit_limit": 5000.0,
    "tenant_id": "tenant_abc123",
    "permission_names": ["secure_chat", "app_builder", "workflow_management"]
  }'

Response (201 Created)

{
  "id": "role_c4m8n1q6",
  "name": "engineering-lead",
  "display_name": "Engineering Lead",
  "description": "Custom role for engineering team leads",
  "user_credit_limit": 5000.0,
  "role_source": "custom",
  "scope": "tenant",
  "permissions_count": 3,
  "permissions_preview": ["Secure Chat", "App Builder", "Workflow Management"],
  "assigned_users_count": 0,
  "permissions": [
    {
      "name": "secure_chat",
      "printable_name": "Secure Chat",
      "description": "Access to the secure AI chat",
      "scope": "entity",
      "tags": ["chat"],
      "user_selectable": true
    }
  ]
}

Update Custom Role

Update the display name, description, or credit limit of a custom role.

Endpoint

PATCH /v1/admin/roles/custom/{role_id}

Path Parameters

  • role_id (required): Role HashID (e.g., "role_c4m8n1q6")

Request Body

All fields are optional — provide only the fields you want to update.

  • display_name (optional): Human-readable name
  • description (optional): Role description
  • user_credit_limit (optional): Per-user credit limit
{
  "display_name": "Senior Engineer",
  "user_credit_limit": 10000.0
}

Example Request

curl -X PATCH 'https://ai.hatz.ai/v1/admin/roles/custom/role_c4m8n1q6' \
  -H 'X-API-Key: $HATZ_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "display_name": "Senior Engineer",
    "user_credit_limit": 10000.0
  }'

Response

{
  "id": "role_c4m8n1q6",
  "name": "engineering-lead",
  "display_name": "Senior Engineer",
  "description": "Custom role for engineering team leads",
  "user_credit_limit": 10000.0,
  "role_source": "custom",
  "scope": "tenant",
  "permissions_count": 3,
  "permissions_preview": ["Secure Chat", "App Builder", "Workflow Management"],
  "assigned_users_count": 0,
  "permissions": []
}

Delete Custom Role

Delete a custom role. Returns 409 Conflict if users are currently assigned to the role.

Endpoint

DELETE /v1/admin/roles/custom/{role_id}

Path Parameters

  • role_id (required): Role HashID (e.g., "role_c4m8n1q6")

Example Request

curl -X DELETE 'https://ai.hatz.ai/v1/admin/roles/custom/role_c4m8n1q6' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response (204 No Content)

No response body.

Error Responses

  • 409 — Role has users assigned and cannot be deleted

Set Custom Role Permissions

Replace the full set of permissions for a custom role. This is a full replacement — any permissions not included in the request will be removed.

Endpoint

PUT /v1/admin/roles/custom/{role_id}/permissions

Path Parameters

  • role_id (required): Role HashID (e.g., "role_c4m8n1q6")

Query Parameters

  • limit (optional): Maximum number of permissions to return (1-200, default: 10)
  • offset (optional): Number of permissions to skip (default: 0)

Request Body

  • permission_names (required): List of permission slugs to assign
{
  "permission_names": ["secure_chat", "app_builder", "workflow_management", "usage_analytics"]
}

Example Request

curl -X PUT 'https://ai.hatz.ai/v1/admin/roles/custom/role_c4m8n1q6/permissions' \
  -H 'X-API-Key: $HATZ_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "permission_names": ["secure_chat", "app_builder", "workflow_management"]
  }'

Response

{
  "permissions": [
    {
      "name": "secure_chat",
      "printable_name": "Secure Chat",
      "description": "Access to the secure AI chat",
      "scope": "entity",
      "tags": ["chat"],
      "user_selectable": true
    },
    {
      "name": "app_builder",
      "printable_name": "App Builder",
      "description": "Create and manage apps",
      "scope": "entity",
      "tags": ["apps"],
      "user_selectable": true
    }
  ],
  "total_count": 3
}

Duplicate Custom Role

Duplicate a custom role, copying all of its permissions to the new role.

Endpoint

POST /v1/admin/roles/custom/{role_id}/duplicate

Path Parameters

  • role_id (required): Role HashID of the role to duplicate (e.g., "role_c4m8n1q6")

Request Body

All fields are optional.

  • name (optional): Slug for the new role; defaults to the original name with "-copy" appended
  • tenant_id (optional): Tenant HashID to scope the duplicate; omit for MSP-wide
{
  "name": "engineering-lead-v2",
  "tenant_id": "tenant_abc123"
}

Example Request

curl -X POST 'https://ai.hatz.ai/v1/admin/roles/custom/role_c4m8n1q6/duplicate' \
  -H 'X-API-Key: $HATZ_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "engineering-lead-v2"
  }'

Response (201 Created)

{
  "id": "role_d9k3w7t2",
  "name": "engineering-lead-v2",
  "display_name": "Senior Engineer (Copy)",
  "description": "Custom role for engineering team leads",
  "user_credit_limit": 10000.0,
  "role_source": "custom",
  "scope": "tenant",
  "permissions_count": 3,
  "permissions_preview": ["Secure Chat", "App Builder", "Workflow Management"],
  "assigned_users_count": 0,
  "permissions": []
}

List Permissions

List the available user-selectable permissions. When tenant_id is provided, the scope may widen for internal MSP tenants.

Endpoint

GET /v1/admin/permissions

Query Parameters

  • tenant_id (optional): Tenant HashID — widens scope for internal MSP tenant
  • limit (optional): Maximum number of permissions to return (1-200, default: 10)
  • offset (optional): Number of permissions to skip (default: 0)

Example Query

curl 'https://ai.hatz.ai/v1/admin/permissions?limit=50&offset=0' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response

{
  "permissions": [
    {
      "name": "secure_chat",
      "printable_name": "Secure Chat",
      "description": "Access to the secure AI chat",
      "scope": "entity",
      "tags": ["chat"],
      "user_selectable": true
    },
    {
      "name": "app_builder",
      "printable_name": "App Builder",
      "description": "Create and manage apps",
      "scope": "entity",
      "tags": ["apps"],
      "user_selectable": true
    }
  ],
  "total_count": 24
}

List Tenant Assignable Roles

List all roles assignable within a specific tenant context. Returns default roles plus MSP-wide and tenant-scoped custom roles.

Endpoint

GET /v1/admin/tenants/{tenant_id}/roles

Path Parameters

  • tenant_id (required): Tenant HashID (e.g., "tenant_abc123")

Query Parameters

  • limit (optional): Maximum number of roles to return (1-500, default: 100)
  • offset (optional): Number of roles to skip (default: 0)

Example Query

curl 'https://ai.hatz.ai/v1/admin/tenants/tenant_abc123/roles?limit=50&offset=0' \
  -H 'X-API-Key: $HATZ_API_KEY'

Response

{
  "roles": [
    {
      "id": "role_a3k9x2m8",
      "name": "general_user",
      "display_name": "General User",
      "description": "Standard user access",
      "user_credit_limit": null,
      "role_source": "default",
      "scope": null,
      "permissions_count": 12,
      "permissions_preview": [],
      "assigned_users_count": null
    },
    {
      "id": "role_b7j2y5p1",
      "name": "msp-power-user",
      "display_name": "MSP Power User",
      "description": "MSP-wide custom role",
      "user_credit_limit": 8000.0,
      "role_source": "custom",
      "scope": "msp",
      "permissions_count": 15,
      "permissions_preview": [],
      "assigned_users_count": null
    },
    {
      "id": "role_c4m8n1q6",
      "name": "engineering-lead",
      "display_name": "Engineering Lead",
      "description": "Tenant-scoped custom role",
      "user_credit_limit": 5000.0,
      "role_source": "custom",
      "scope": "tenant",
      "permissions_count": 18,
      "permissions_preview": [],
      "assigned_users_count": null
    }
  ],
  "total_count": 3
}