# Staff

Staff are the people who run a site day to day: they open its private
paths, such as `/admin/`, and nothing else. A staff member is not a
[collaborator](/api/collaborators). They cannot edit, publish or read the
site through the API.

The staff list is about running the site. Owner and collaborator are about
building it. They give no labels and no permissions: for those, the owner
adds them to the staff list too. A private path can still let a role in
by name.

The site declares its private paths, and the roles or labels each one
needs, in
`clave.site.json`. See [Code in a site](/concepts/code).

## Add or change a staff member

`POST /v1/sites/{id}/staff`. Only the owner may call it.

```json
{ "email": "desk@example.com", "labels": ["front-desk"], "permissions": ["payments:refund"] }
```

The person needs a Clave account first. Call it again to change the labels
or the permissions.

- `labels` are the site's own words. The site's code reads them and
  decides what each one may do with the site's own data.
- `permissions` are the platform's. `payments:refund` lets the person give
  the site's money back through the site's code. The owner gets it the
  same way: add the owner's own address with the permission.

`GET /v1/sites/{id}/staff` lists them. `DELETE /v1/sites/{id}/staff/{account_id}`
removes one. A removed person keeps their open page for up to an hour, but
every refund reads the staff list at that moment, so they lose money
rights at once. A change of labels reaches the person at their next
sign-in.

## How staff sign in

1. A staff member opens a private path, for example `/admin/`.
2. The site sends them to Clave to sign in with their own account.
3. Clave sends them back, and the site keeps a session on its own address
   for one hour. `/clave/signout` ends it.
4. If the path names roles or labels, a person with none of them gets a
   403.

On each request, the site's code gets a `Clave-Identity` header: a signed
token that says who the person is, their role, their labels and their
permissions. It lives five minutes. The site's code reads it for "who is
this", and forwards it to a guarded call:

`POST /v1/runtime/payments/{id}/refund` with the site key, the
`Clave-Identity` header and `{ "amount_minor": 1000 }`. The platform checks
the token, then the person's permissions now, then that the payment is this
site's and the amount is not more than was paid. See
[Runtime](/api/runtime).

An action gets the header too, because the session works on every path.
Check it in the action: anyone can post to `/_actions/name`.

## The Clave-Identity token

The token is `v1.<payload>.<signature>`. The payload is base64url JSON
with no padding:

| Field | Holds |
|---|---|
| `kind` | `identity` |
| `account` | the person's Clave account id |
| `email` | the person's mail address |
| `site`, `host` | the site and the hostname the token is for |
| `role` | `owner`, `collaborator` or `staff`. It gives no permissions: the site's code decides what it means |
| `labels` | the site's own labels, from the staff list |
| `perms` | the platform permissions, such as `payments:refund` |
| `via` | `browser` or `agent` |
| `exp` | when it stops being valid, in Unix seconds |

The signature is the platform's own. The site's code cannot check it,
because it does not get the key. It does not need to: on every path,
public ones too, the platform removes a `Clave-Identity` that a visitor
sent. The header the site's code gets is always the platform's. Read the
payload, and check `exp` and `host`.

The token says who the person was when it was made. For money, the
platform reads the staff list again at the call.

`POST /v1/site-signin/exchange` is the dispatcher's own call. It takes a
platform signature, and nothing else can call it.

---

## Where this page sits

This is one page of the Clave documentation.
Read it as a web page at https://docs.heyclave.com/api/staff.
Every page has a `.md` address, and https://docs.heyclave.com/llms.txt lists them all.

- Previous: [Runtime](https://docs.heyclave.com/api/runtime.md)
- Next: [Call the site](https://docs.heyclave.com/api/call.md)
- Index: [Overview](https://docs.heyclave.com/index.md)
