---
title: "Delete a role"
description: "Any role but the owner, and only once you have said where its holders go."
url: "https://openemail.uk/docs/api/roles/delete"
area: "API"
category: "Roles & access"
---

# Delete a role

Any role but the owner, and only once you have said where its holders go.

`DELETE /roles/{id}`

## DELETE /roles/{id}

Any role but the owner, and only once you have said where its holders go.

## Example

Needs `roles:write`. `reassignTo` names the role every member and every API key on this one moves to.

**curl**

```
curl -X DELETE "$OE/roles/role_2b81de079c1f0a4b7e05d386?reassignTo=role_c40a95f21cc65d31c2a89e07" \
  -H "$AUTH"
```

**Response**

```
{
  "object": "role",
  "id": "role_2b81de079c1f0a4b7e05d386",
  "deleted": true,
  "reassigned": 3,
  "keysReassigned": 1
}
```

> `reassignTo` travels as a QUERY parameter rather than in a body. A body on DELETE is legal and widely unsupported (several runtimes drop it and so do a number of proxies), and a dropped `reassignTo` is indistinguishable from one that was never sent, which is precisely the case this endpoint refuses rather than guesses at.

> It is required the moment anybody holds the role: without it, `role_in_use`, a 409, carrying `param: "reassignTo"`, which is the actual fix. The column is `ON DELETE RESTRICT` underneath, so there is no path where deleting a role quietly changes what somebody can do.

> API keys are re-pointed rather than orphaned, and that is the subtle half. A key whose role vanished would fall back to a NULL ceiling, and a null ceiling is WIDER than the role that just went, so deleting a restrictive role would otherwise quietly promote every key it was capping.

> The two counts are separate because they are two different things to go and check: `reassigned` is people, who will notice, and `keysReassigned` is programs, which will not.

> The owner role cannot be deleted (`role_undeletable`, a 409) because it names the account the workspace is keyed on rather than a job anybody does. Every other role can go, the seeded `Admin`, `Member`, `Viewer`, `Developer` and `Billing` as much as one somebody wrote: they are a starting point, and a workspace with no integrations has no use for a `Developer` row it is not allowed to be rid of. Check `deletable` before offering the button; only the owner answers false.

> Deleting a SEEDED role is not permanent, so do not word the dialog as though it were. `GET /roles` re-seeds whatever template row is missing, and a delete leaves no tombstone, so the next list read puts `Developer` back under a new `id`. Renaming it is what makes it stop coming back (a renamed row keeps its `builtin` and goes on conflicting with the seed), or another role taking the name will do it, since the seeder skips a row whose name is spoken for.
