# Staff roles and permissions

URL: https://docs.spacerun.co/docs/platform/guides/staff-permissions

> Create roles, grant permission keys, assign staff access, and troubleshoot permission failures.

Staff calls use a normal user Bearer JWT plus permission checks; there is no separate Platform staff API key. Prerequisites: an operator with `roles.write` and `roles.assign`, an existing target user, and [apiRequest](https://docs.spacerun.co/docs/platform/guides/quickstart).

## Create and assign a role

1. Read the permission catalog via [getAdminPermissionMatrix](https://docs.spacerun.co/docs/platform/reference/roles/getAdminPermissionMatrix) and choose the minimum keys for the workflow.
2. Create a role using [createAdminRole](https://docs.spacerun.co/docs/platform/reference/roles/createAdminRole).
3. Replace its permission set with [setAdminRolePermissions](https://docs.spacerun.co/docs/platform/reference/roles/setAdminRolePermissions).
4. Grant it to the user through [assignAdminRole](https://docs.spacerun.co/docs/platform/reference/roles/assignAdminRole).

```ts
const role = await apiRequest("/v1/admin/roles", {
  method: "POST", body: JSON.stringify({ key: "catalog-editor", name: "Catalog editor" }),
});
await apiRequest(`/v1/admin/roles/${role.id}/permissions`, {
  method: "PUT", body: JSON.stringify({ keys: ["store.read", "store.write"] }),
});
await apiRequest("/v1/admin/roles/assign", {
  method: "POST",
  body: JSON.stringify({
    user_id: "3f6c2a1e-8b4d-4e7a-9c1f-2d5b6a7e8f90",
    role_key: "catalog-editor", reason: "Catalog publishing duties",
  }),
});
```

Replace the synthetic user ID with an existing user. Permission replacement and role assignment return 204. The assignee should obtain a fresh access token after changes and verify [getMyPermissions](https://docs.spacerun.co/docs/platform/reference/profile/getMyPermissions).

## Permission semantics and failures

A route requiring several keys uses **OR** semantics: one matching key is enough. `*` matches all permissions and `<resource>.*` matches that resource. Role membership alone is not a substitute for the operation's required keys.

```json
{"error":"forbidden","details":{"perm":"announcements.write | email.send"}}
```

This means either listed permission is accepted. A missing/expired token is 401; valid authentication without a matching permission is 403. Confirm the token belongs to the intended user, refresh it after role changes, inspect effective keys, and check the operation's Authentication section. Use [revokeAdminRole](https://docs.spacerun.co/docs/platform/reference/roles/revokeAdminRole) to remove a grant. Bulk staff mutations return per-user results; a 200 does not mean every item succeeded.
