# Roles

## List

**get** `/zones/{zoneId}/roles`

Returns the roles defined in the specified zone. The full result set is currently returned in a single page; the `after`/`before`/`limit` cursor parameters are reserved and not yet enforced, and `pagination` cursors are always null.

### Path Parameters

- `zoneId: string`

### Query Parameters

- `after: optional string`

  Cursor for forward pagination

- `before: optional string`

  Cursor for backward pagination

- `"expand[]": optional "total_count" or array of "total_count"`

  - `UnionMember0 = "total_count"`

    - `"total_count"`

  - `UnionMember1 = array of "total_count"`

    - `"total_count"`

- `identifier: optional string`

  Filter roles by identifier

- `limit: optional number`

  Maximum number of items to return

### Returns

- `items: array of Role`

  - `id: string`

    Unique identifier of the role

  - `created_at: string`

    Entity creation timestamp

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `owner_type: "platform" or "customer"`

    Who owns this role. Platform-owned roles are managed by Keycard and cannot be modified or deleted via the API; customer-owned roles are user-created.

    - `"platform"`

    - `"customer"`

  - `updated_at: string`

    Entity update timestamp

  - `zone_id: string`

    Zone this role belongs to

  - `description: optional string`

    Human-readable description

- `pagination: object { after_cursor, before_cursor, total_count }`

  Cursor-based pagination metadata

  - `after_cursor: string`

    An opaque cursor used for paginating through a list of results

  - `before_cursor: string`

    An opaque cursor used for paginating through a list of results

  - `total_count: optional number`

    Total number of items matching the query. Only included when expand[]=total_count is requested.

### Example

```http
curl https://api.keycard.ai/zones/$ZONE_ID/roles \
    -H "Authorization: Bearer $KEYCARD_API_API_KEY"
```

## Create

**post** `/zones/{zoneId}/roles`

Creates a new customer-owned role in the specified zone. The owner_type is always customer; platform roles are managed by Keycard.

### Path Parameters

- `zoneId: string`

### Body Parameters

- `identifier: string`

  Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

- `description: optional string`

  Human-readable description

### Returns

- `Role = object { id, created_at, identifier, 4 more }`

  A role that can be assigned to users within a zone.

  - `id: string`

    Unique identifier of the role

  - `created_at: string`

    Entity creation timestamp

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `owner_type: "platform" or "customer"`

    Who owns this role. Platform-owned roles are managed by Keycard and cannot be modified or deleted via the API; customer-owned roles are user-created.

    - `"platform"`

    - `"customer"`

  - `updated_at: string`

    Entity update timestamp

  - `zone_id: string`

    Zone this role belongs to

  - `description: optional string`

    Human-readable description

### Example

```http
curl https://api.keycard.ai/zones/$ZONE_ID/roles \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $KEYCARD_API_API_KEY" \
    -d '{
          "identifier": "identifier"
        }'
```

## Retrieve

**get** `/zones/{zoneId}/roles/{roleId}`

Returns details of a specific role by ID

### Path Parameters

- `zoneId: string`

- `roleId: string`

### Returns

- `Role = object { id, created_at, identifier, 4 more }`

  A role that can be assigned to users within a zone.

  - `id: string`

    Unique identifier of the role

  - `created_at: string`

    Entity creation timestamp

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `owner_type: "platform" or "customer"`

    Who owns this role. Platform-owned roles are managed by Keycard and cannot be modified or deleted via the API; customer-owned roles are user-created.

    - `"platform"`

    - `"customer"`

  - `updated_at: string`

    Entity update timestamp

  - `zone_id: string`

    Zone this role belongs to

  - `description: optional string`

    Human-readable description

### Example

```http
curl https://api.keycard.ai/zones/$ZONE_ID/roles/$ROLE_ID \
    -H "Authorization: Bearer $KEYCARD_API_API_KEY"
```

## Update

**patch** `/zones/{zoneId}/roles/{roleId}`

Updates a customer-owned role's description. The identifier is immutable, and platform-owned roles cannot be modified.

### Path Parameters

- `zoneId: string`

- `roleId: string`

### Body Parameters

- `description: optional string`

  Human-readable description (set to null to unset)

### Returns

- `Role = object { id, created_at, identifier, 4 more }`

  A role that can be assigned to users within a zone.

  - `id: string`

    Unique identifier of the role

  - `created_at: string`

    Entity creation timestamp

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `owner_type: "platform" or "customer"`

    Who owns this role. Platform-owned roles are managed by Keycard and cannot be modified or deleted via the API; customer-owned roles are user-created.

    - `"platform"`

    - `"customer"`

  - `updated_at: string`

    Entity update timestamp

  - `zone_id: string`

    Zone this role belongs to

  - `description: optional string`

    Human-readable description

### Example

```http
curl https://api.keycard.ai/zones/$ZONE_ID/roles/$ROLE_ID \
    -X PATCH \
    -H "Authorization: Bearer $KEYCARD_API_API_KEY"
```

## Delete

**delete** `/zones/{zoneId}/roles/{roleId}`

Permanently deletes a customer-owned role. Platform-owned roles cannot be deleted, and a role with existing assignments returns 409.

### Path Parameters

- `zoneId: string`

- `roleId: string`

### Example

```http
curl https://api.keycard.ai/zones/$ZONE_ID/roles/$ROLE_ID \
    -X DELETE \
    -H "Authorization: Bearer $KEYCARD_API_API_KEY"
```

## Domain Types

### Role

- `Role = object { id, created_at, identifier, 4 more }`

  A role that can be assigned to users within a zone.

  - `id: string`

    Unique identifier of the role

  - `created_at: string`

    Entity creation timestamp

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `owner_type: "platform" or "customer"`

    Who owns this role. Platform-owned roles are managed by Keycard and cannot be modified or deleted via the API; customer-owned roles are user-created.

    - `"platform"`

    - `"customer"`

  - `updated_at: string`

    Entity update timestamp

  - `zone_id: string`

    Zone this role belongs to

  - `description: optional string`

    Human-readable description

### Role Create

- `RoleCreate = object { identifier, description }`

  Schema for creating a new role

  - `identifier: string`

    Role identifier: a lowercase slug (letters and digits separated by single hyphens or underscores), unique per owner type within a zone. Role identifiers surface in policy evaluation, so the slug restriction keeps them unambiguous in policy text.

  - `description: optional string`

    Human-readable description

### Role Update

- `RoleUpdate = object { description }`

  Schema for updating an existing role. The role identifier is immutable.

  - `description: optional string`

    Human-readable description (set to null to unset)
