> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ancestraldev.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Avalex Staff API — Manage Accounts and Permissions

> List, update, and deactivate staff accounts via the Avalex API. Assign roles, toggle account status, and delete staff members programmatically.

The `/staff` endpoints let you manage the human operators who access your Avalex dashboard and API. You can list all staff accounts, look up an individual member, reassign roles, deactivate or reactivate accounts, and permanently remove a staff member. All management actions require the `staff:manage` permission, while read-only lookups require `staff:read`.

<Note>
  Creating a new staff account requires a valid, unused registration key. Registration keys are generated by the Master Admin and consumed on first use. See the [Registration Keys](/api/staff/registration-keys) page for details.
</Note>

## Required Permissions

| Action                                 | Permission                               |
| -------------------------------------- | ---------------------------------------- |
| List / retrieve staff                  | `staff:read`                             |
| Update roles, active status, or delete | `staff:manage`                           |
| Register a new staff account           | None — requires a valid registration key |

***

## List All Staff

<ParamField header="Authorization" type="string" required>
  Bearer `<token>` or Basic credentials.
</ParamField>

Returns an array of all staff accounts as `StaffPublicView` objects.

```bash theme={null}
curl http://localhost:8080/staff \
  -H "Authorization: Bearer <token>"
```

**Response — 200 OK**

```json theme={null}
[
  {
    "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
    "username": "newstaff",
    "email": "staff@example.com",
    "roleIds": ["role_support"],
    "active": true
  }
]
```

***

## Get a Staff Member by ID

<ParamField path="id" type="string" required>
  The UUID of the staff member (e.g. `e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef`).
</ParamField>

Returns a single `StaffPublicView`. Responds with `404 Not Found` if no staff member with that ID exists.

```bash theme={null}
curl http://localhost:8080/staff/e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef \
  -H "Authorization: Bearer <token>"
```

**Response — 200 OK**

```json theme={null}
{
  "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
  "username": "newstaff",
  "email": "staff@example.com",
  "roleIds": ["role_support"],
  "active": true
}
```

***

## Update Staff Roles

<ParamField path="id" type="string" required>
  The UUID of the staff member.
</ParamField>

<ParamField body="roleIds" type="string[]" required>
  Complete list of role IDs to assign to this staff member. Replaces the current set entirely.
</ParamField>

Replaces the staff member's role assignments with the provided array. Returns `404 Not Found` if the staff member does not exist.

<Note>
  This endpoint replaces all existing role assignments. To add a role without removing others, retrieve the current `roleIds` first, append the new ID, then submit the full updated array.
</Note>

```bash theme={null}
curl -X PUT http://localhost:8080/staff/e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef/roles \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "roleIds": ["role_support", "role_billing"]
  }'
```

**Response — 200 OK**

```json theme={null}
{
  "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
  "username": "newstaff",
  "email": "staff@example.com",
  "roleIds": ["role_support", "role_billing"],
  "active": true
}
```

***

## Update Staff Active Status

<ParamField path="id" type="string" required>
  The UUID of the staff member.
</ParamField>

<ParamField body="active" type="boolean" required>
  Set to `false` to deactivate the account, or `true` to reactivate it.
</ParamField>

Toggles the active status of a staff account. Deactivated accounts cannot authenticate or use the API. Returns `404 Not Found` if the staff member does not exist.

```bash theme={null}
curl -X PUT http://localhost:8080/staff/e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef/active \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "active": false
  }'
```

**Response — 200 OK**

```json theme={null}
{
  "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
  "username": "newstaff",
  "email": "staff@example.com",
  "roleIds": ["role_support"],
  "active": false
}
```

***

## Delete a Staff Member

<ParamField path="id" type="string" required>
  The UUID of the staff member to delete.
</ParamField>

Permanently removes the staff account. Returns `204 No Content` on success and `404 Not Found` if the ID does not exist.

<Warning>
  This action is irreversible. The deleted staff member will need to register a new account using a fresh registration key if access is required again.
</Warning>

```bash theme={null}
curl -X DELETE http://localhost:8080/staff/e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef \
  -H "Authorization: Bearer <token>"
```

**Response — 204 No Content**

***

## Register a New Staff Member

This endpoint is public and does not require an authenticated session, but it does require a valid, unused registration key issued by the Master Admin.

<ParamField body="registrationKey" type="string" required>
  A single-use registration key generated via `POST /admin/registration-keys`.
</ParamField>

<ParamField body="username" type="string" required>
  Desired username for the new staff account.
</ParamField>

<ParamField body="email" type="string" required>
  Email address for the new staff account.
</ParamField>

<ParamField body="password" type="string" required>
  Password for the new account. Must be at least 8 characters long.
</ParamField>

<ParamField body="roleIds" type="string[]" required>
  Array of role IDs to assign to the new staff member on registration.
</ParamField>

Creates a new staff account and returns a `StaffPublicView`. The registration key is consumed and cannot be reused.

```bash theme={null}
curl -X POST http://localhost:8080/staff/register \
  -H "Content-Type: application/json" \
  -d '{
    "registrationKey": "a1b2c3d4e5f67890abcdef1234567890",
    "username": "newstaff",
    "email": "staff@example.com",
    "password": "securepassword123",
    "roleIds": ["role_support"]
  }'
```

**Response — 201 Created**

```json theme={null}
{
  "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
  "username": "newstaff",
  "email": "staff@example.com",
  "roleIds": ["role_support"],
  "active": true
}
```

### Error Responses

**400 Bad Request** — Password too short:

```json theme={null}
{
  "error": "Password must be at least 8 characters"
}
```

**403 Forbidden** — Key not recognised:

```json theme={null}
{
  "error": "Invalid registration key"
}
```

**403 Forbidden** — Key already consumed:

```json theme={null}
{
  "error": "This registration key has already been used"
}
```

***

## StaffPublicView Schema

<Expandable title="StaffPublicView fields">
  <ResponseField name="id" type="string">
    UUID assigned to the staff member on registration (e.g. `e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef`).
  </ResponseField>

  <ResponseField name="username" type="string">
    Unique username chosen at registration.
  </ResponseField>

  <ResponseField name="email" type="string">
    Email address associated with the staff account.
  </ResponseField>

  <ResponseField name="roleIds" type="string[]">
    Array of role IDs currently assigned to this staff member. Roles determine which permissions the account holds.
  </ResponseField>

  <ResponseField name="active" type="boolean">
    Whether the account is currently active. Inactive accounts cannot authenticate.
  </ResponseField>
</Expandable>

### Full Schema Example

```json theme={null}
{
  "id": "e9f0d1c2-b3a4-5678-cdef-90ab12cd34ef",
  "username": "newstaff",
  "email": "staff@example.com",
  "roleIds": ["role_support"],
  "active": true
}
```
