---
title: "Add and remove role permissions in one call"
method: PATCH
path: "/roles/{roleId}/permissions/bulk"
tags: ["Role"]
---

# Add and remove role permissions in one call

`PATCH /roles/{roleId}/permissions/bulk`

Modifies the permission set of the role identified by `roleId` by adding and/or removing permissions in a single request. This is not a single atomic operation: the implementation reads the role's current permissions, merges the requested `add`/`remove` changes, and then writes the result back as a separate step (no transaction or rollback); concurrent calls for the same role may race, and one call's changes can be silently overwritten by another (tracked in CP-36406). Use this instead of separate add/remove calls when you need to both grant and revoke permissions in one operation; to only add permissions use `POST /roles/{roleId}/permissions`. Requires the `tenant-id` header (returns 400 if absent or blank). The request body accepts two optional arrays of permission ID strings: `add` (permissions to grant) and `remove` (permissions to revoke). Permissions in `remove` that are not currently assigned are silently ignored. If both `add` and `remove` include the same ID, the permission is added (remove is applied before add). Returns 200 with the complete, updated list of all permissions assigned to the role after the operation. Note: if the role does not exist, the current implementation returns 500 rather than 404 (tracked in CP-36405).

## Path parameters

- `roleId` string, required

## Headers

- `tenant-id` string

## Request body

- RolePermissionBulkUpdateRequest — Request body for adding and/or removing permissions from a role in a single operation
  - `add` string[] — IDs of permissions to add to the role. Omit or leave empty if only removing.
  - `remove` string[] — IDs of permissions to remove from the role. Omit or leave empty if only adding.

## Response `200`

Permissions updated successfully

- PermissionResponseDto[]
  - `id` string — Server-assigned unique identifier for the permission.
  - `resource` string — Name of the resource this permission governs (e.g. 'user', 'roster'). Mirrors the resource value supplied when the permission was created or last replaced.
  - `action` string — Name of the action this permission grants on the resource (e.g. 'read', 'create'). Mirrors the action value supplied when the permission was created or last replaced.
  - `description` string — Human-readable explanation of what the permission allows. Optional; may be null if it was not supplied at creation.
  - `createdAt` string, date-time
  - `updatedAt` string, date-time

## Other responses

- `400` — Bad request - Invalid request data or missing required fields
- `401` — Authentication required - Valid authentication token is missing or invalid
- `403` — Forbidden - User does not have the required permissions to update role permissions
- `500` — Internal server error - An unexpected error occurred while processing the request. No response body is returned. Note: a non-existent role ID currently also surfaces here as a 500 rather than a 404, since not-found conditions are not distinguished from other failures (tracked in CP-36405).

---

[API](https://skmtc.net/certifyos/apis/certify-api-layer.md) · [All operations](https://skmtc.net/certifyos/apis/certify-api-layer/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/certifyos/certify-api-layer/revisions/563848e0ecc0/schema)
