---
title: "Change a custom role"
method: PATCH
path: "/roles/{id}"
tags: ["Roles and members"]
---

# Change a custom role

`PATCH /roles/{id}`

## Request

- Base URL: `https://api.primitive.dev/v1`
- URL: `https://api.primitive.dev/v1/roles/{id}`
- Auth: HTTP bearer

A new version of the role. Every holder whose access shrinks goes through the reduction path. mail_scope follows the same rules as creating a role; a role whose stored scope cannot be read must be sent a new mail_scope, otherwise 400 `validation_error` with `details.reason` `invalid_mail_scope`.  A personal mailbox the new version adds must be the author's own, and every holder must be the member of each personal mailbox it names: otherwise 403 `grant_forbidden` with `details.reason` `personal_mailbox_member_only`. Person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up of purpose `roles.write` (the person confirms at the step_up_url a 403 step_up_required answer carries, which names this client, then send the token in the Primitive-Step-Up header; the token works only with the client it was confirmed for). Needs roles:assign. API keys are refused.

## Path parameters

- `id` string, uuid, required

## Request body

- UpdateRoleRequest
  - `name` string
  - `description` string, nullable
  - `permissions` string[]
  - `mail_scope` union
    - 'org'
    - object
      - `addresses` string[]
      - `domains` string[]
      - `depth` 'metadata' | 'content' | 'raw', required

## Response `200`

Change a custom role

- object
  - `success` true, required
  - `data` UpdateRoleResult, required
    - `id` string, required
    - `key` string, required
    - `kind` 'builtin' | 'template' | 'custom', required
    - `name` string, required
    - `description` string, nullable, required
    - `permissions` string[], required
    - `mail_scope` unknown, required
    - `version` number, required
    - `catalog_version` string, nullable, required
    - `predates_catalog` boolean, required

## Other responses

- `400`: Invalid request parameters
- `401`: Invalid or missing API key
- `403`: Authenticated caller lacks permission for the operation
- `404`: feature_disabled: the feature is not enabled for the organization; or not_found: the item the path names does not exist.
- `409`: conflict: the item changed while you edited it, or a member was removed and added back. Look again, then retry.
- `429`: Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.

---

[API](https://skmtc.dev/primitive/apis/primitive-api.md) - [All operations](https://skmtc.dev/primitive/apis/primitive-api/llms.txt) - [OpenAPI document](https://skmtc.dev/primitive/apis/primitive-api/revisions/bce409c97acb?raw)
