> This page is for Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.emnify.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.emnify.com/_mcp/server.

# Update a custom role

PATCH https://cdn.emnify.net/api/v1/organisation/{orgId}/role/{roleId}
Content-Type: application/json

Required permissions Beta [Learn more](/developers/api-guidelines/permissions#how-permissions-work)`Organisation.Role` + `Update`Roles: AdministratorPartially updates a custom role.
System roles can't be modified.When you provide `permission_ids` or `permissions`, the field replaces the existing permission list.
The two fields are mutually exclusive.
Retrieve the valid permissions with `GET /api/v1/organisation/{orgId}/permission`.Use `my` in place of a numeric `orgId` to target the caller's own Workspace.

Reference: https://docs.emnify.com/developers/api/permission-and-role-management/update-custom-role

## Authentication

- `Authorization` header (bearer token, required) — An `auth_token` should be provided to authenticate a session. To obtain an `auth_token`, see the [`/api/v1/authenticate` **POST** request](/developers/api/authentication/authenticate).

## Request

### Path parameters

- `roleId` (integer, required) — Numeric identifier of the role.
- `orgId` (ApiV1OrganisationOrgIdRoleRoleIdPatchParametersOrgId, required) — Workspace identifier. Either a positive integer organization ID, or the literal string `my` to target the caller's own Workspace.

### Body (application/json)

This endpoint expects an UpdateCustomRoleInputDto.

- `name` (string, optional) — New unique role name within the Workspace. Use letters, digits, spaces, dashes, underscores, ampersands, apostrophes, and parentheses. Leading and trailing whitespace is trimmed before validation and storage. Omit the field to leave the name unchanged, because an explicit `null` is rejected.
- `description` (string, optional, nullable) — Free-text description of the role. Pass `null` to clear it, which stores an empty string. When provided, it must be 2 to 250 characters. Leading and trailing whitespace is trimmed before validation and storage.
- `permission_ids` (list of double, optional) — When provided, replaces the existing permission list. Mutually exclusive with `permissions`. Deprecated or deleted permissions are rejected. Omit the field to leave assignments unchanged, and send `[]` to clear them, because an explicit `null` is rejected.
- `permissions` (list of PermissionRefInputDto, optional) — Resource and action pairs replacing the existing permission list, resolved to permission IDs on the server. Mutually exclusive with `permission_ids`. Deprecated or deleted permissions are rejected. Omit the field to leave assignments unchanged, and send `[]` to clear them, because an explicit `null` is rejected.

## Response

### 200

Successful response.

- `id` (double, required) — Unique role identifier.
- `name` (string, required) — Display name of the role.
- `name_translation_key` (string, required, nullable) — Translation key for the role name. Set for system roles only.
- `description` (string, required) — Human-readable description of the role. An empty string when no description has been set.
- `description_translation_key` (string, required, nullable) — Translation key for the role description. Set for system roles only.
- `user_count` (double, required) — Number of users assigned to this role in the Workspace.
- `type` (enum, required) — Whether this is a system-defined role or an organization's custom role.
  - Allowed values: `system`, `custom`
- `is_system_role` (boolean, required) — True for built-in system roles, which can't be modified or deleted.
- `permissions` (list of RolePermissionOutputDto, optional) — Full list of permissions assigned to this role.

## Errors

### 400 Bad Request Error

Validation error. For example, an invalid name or description, or a referenced permission that isn't available to the Workspace's organization type. Supplying both `permission_ids` and `permissions` in the same request is also rejected, because the two fields are mutually exclusive.

- `status_code` (integer, optional)
- `message` (string, optional)

### 404 Not Found Error

Role not found.

- `status_code` (integer, optional)
- `message` (string, optional)

### 409 Conflict Error

A role with this name already exists in the Workspace.

- `error_code` (integer, optional)
- `error_token` (string, optional)
- `message` (string, optional)

### 422 Unprocessable Entity Error

Business rule violation. For example, an attempt to modify a system role, or `permission_ids` or `permissions` references a permission that is unknown, deprecated, deleted, or granted globally.

- `status_code` (integer, optional)
- `message` (string, optional)

## Types

### PermissionRefInputDto

- `resource` (string, required) — Resource the permission applies to.
- `action` (string, required) — Action the permission grants on the resource.

### ApiV1OrganisationOrgIdRoleRoleIdPatchParametersOrgId

### RolePermissionOutputDto

- `id` (double, required) — Unique permission identifier.
- `resource` (string, required) — Resource the permission applies to.
- `action` (string, required) — Action the permission grants on the resource.

## Examples

### Permission and role management_updateCustomRole_example

**Response**

```json
{
  "id": 102,
  "name": "Fleet operator v2",
  "name_translation_key": null,
  "description": "Updated scope after the Q3 review.",
  "description_translation_key": null,
  "user_count": 2,
  "type": "custom",
  "is_system_role": false,
  "permissions": [
    {
      "id": 2,
      "resource": "Endpoint",
      "action": "List"
    },
    {
      "id": 3,
      "resource": "Endpoint",
      "action": "Create"
    },
    {
      "id": 4,
      "resource": "Endpoint",
      "action": "Delete"
    },
    {
      "id": 5,
      "resource": "ServicePolicy",
      "action": "List"
    }
  ]
}
```

**SDK Code**

```python Permission and role management_updateCustomRole_example
import requests

url = "https://cdn.emnify.net/api/v1/organisation/my/role/12"

headers = {"Authorization": "Bearer <token>"}

response = requests.patch(url, headers=headers)

print(response.json())
```

```javascript Permission and role management_updateCustomRole_example
const url = 'https://cdn.emnify.net/api/v1/organisation/my/role/12';
const options = {method: 'PATCH', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Permission and role management_updateCustomRole_example
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://cdn.emnify.net/api/v1/organisation/my/role/12"

	req, _ := http.NewRequest("PATCH", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Permission and role management_updateCustomRole_example
require 'uri'
require 'net/http'

url = URI("https://cdn.emnify.net/api/v1/organisation/my/role/12")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java Permission and role management_updateCustomRole_example
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.patch("https://cdn.emnify.net/api/v1/organisation/my/role/12")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php Permission and role management_updateCustomRole_example
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://cdn.emnify.net/api/v1/organisation/my/role/12', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp Permission and role management_updateCustomRole_example
using RestSharp;

var client = new RestClient("https://cdn.emnify.net/api/v1/organisation/my/role/12");
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift Permission and role management_updateCustomRole_example
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://cdn.emnify.net/api/v1/organisation/my/role/12")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Permissions By ID

**Request**

```json
{
  "name": "Fleet operator v2",
  "permission_ids": [
    2,
    3,
    5,
    7
  ]
}
```

**Response**

```json
{
  "id": 102,
  "name": "Fleet operator v2",
  "name_translation_key": null,
  "description": "Updated scope after the Q3 review.",
  "description_translation_key": null,
  "user_count": 2,
  "type": "custom",
  "is_system_role": false,
  "permissions": [
    {
      "id": 2,
      "resource": "Endpoint",
      "action": "List"
    },
    {
      "id": 3,
      "resource": "Endpoint",
      "action": "Create"
    },
    {
      "id": 4,
      "resource": "Endpoint",
      "action": "Delete"
    },
    {
      "id": 5,
      "resource": "ServicePolicy",
      "action": "List"
    }
  ]
}
```

**SDK Code**

```python Permissions By ID
import requests

url = "https://cdn.emnify.net/api/v1/organisation/my/role/12"

payload = {
    "name": "Fleet operator v2",
    "permission_ids": [2, 3, 5, 7]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())
```

```javascript Permissions By ID
const url = 'https://cdn.emnify.net/api/v1/organisation/my/role/12';
const options = {
  method: 'PATCH',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"name":"Fleet operator v2","permission_ids":[2,3,5,7]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Permissions By ID
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://cdn.emnify.net/api/v1/organisation/my/role/12"

	payload := strings.NewReader("{\n  \"name\": \"Fleet operator v2\",\n  \"permission_ids\": [\n    2,\n    3,\n    5,\n    7\n  ]\n}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Permissions By ID
require 'uri'
require 'net/http'

url = URI("https://cdn.emnify.net/api/v1/organisation/my/role/12")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"Fleet operator v2\",\n  \"permission_ids\": [\n    2,\n    3,\n    5,\n    7\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Permissions By ID
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.patch("https://cdn.emnify.net/api/v1/organisation/my/role/12")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"Fleet operator v2\",\n  \"permission_ids\": [\n    2,\n    3,\n    5,\n    7\n  ]\n}")
  .asString();
```

```php Permissions By ID
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://cdn.emnify.net/api/v1/organisation/my/role/12', [
  'body' => '{
  "name": "Fleet operator v2",
  "permission_ids": [
    2,
    3,
    5,
    7
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Permissions By ID
using RestSharp;

var client = new RestClient("https://cdn.emnify.net/api/v1/organisation/my/role/12");
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"Fleet operator v2\",\n  \"permission_ids\": [\n    2,\n    3,\n    5,\n    7\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Permissions By ID
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "name": "Fleet operator v2",
  "permission_ids": [2, 3, 5, 7]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://cdn.emnify.net/api/v1/organisation/my/role/12")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Permissions By Resource And Action

**Request**

```json
{
  "name": "Fleet operator v2",
  "permissions": [
    {
      "resource": "Endpoint",
      "action": "List"
    },
    {
      "resource": "Endpoint",
      "action": "Create"
    },
    {
      "resource": "ServicePolicy",
      "action": "List"
    }
  ]
}
```

**Response**

```json
{
  "id": 102,
  "name": "Fleet operator v2",
  "name_translation_key": null,
  "description": "Updated scope after the Q3 review.",
  "description_translation_key": null,
  "user_count": 2,
  "type": "custom",
  "is_system_role": false,
  "permissions": [
    {
      "id": 2,
      "resource": "Endpoint",
      "action": "List"
    },
    {
      "id": 3,
      "resource": "Endpoint",
      "action": "Create"
    },
    {
      "id": 4,
      "resource": "Endpoint",
      "action": "Delete"
    },
    {
      "id": 5,
      "resource": "ServicePolicy",
      "action": "List"
    }
  ]
}
```

**SDK Code**

```python Permissions By Resource And Action
import requests

url = "https://cdn.emnify.net/api/v1/organisation/my/role/12"

payload = {
    "name": "Fleet operator v2",
    "permissions": [
        {
            "resource": "Endpoint",
            "action": "List"
        },
        {
            "resource": "Endpoint",
            "action": "Create"
        },
        {
            "resource": "ServicePolicy",
            "action": "List"
        }
    ]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.patch(url, json=payload, headers=headers)

print(response.json())
```

```javascript Permissions By Resource And Action
const url = 'https://cdn.emnify.net/api/v1/organisation/my/role/12';
const options = {
  method: 'PATCH',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"name":"Fleet operator v2","permissions":[{"resource":"Endpoint","action":"List"},{"resource":"Endpoint","action":"Create"},{"resource":"ServicePolicy","action":"List"}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Permissions By Resource And Action
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://cdn.emnify.net/api/v1/organisation/my/role/12"

	payload := strings.NewReader("{\n  \"name\": \"Fleet operator v2\",\n  \"permissions\": [\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"List\"\n    },\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"Create\"\n    },\n    {\n      \"resource\": \"ServicePolicy\",\n      \"action\": \"List\"\n    }\n  ]\n}")

	req, _ := http.NewRequest("PATCH", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Permissions By Resource And Action
require 'uri'
require 'net/http'

url = URI("https://cdn.emnify.net/api/v1/organisation/my/role/12")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"name\": \"Fleet operator v2\",\n  \"permissions\": [\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"List\"\n    },\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"Create\"\n    },\n    {\n      \"resource\": \"ServicePolicy\",\n      \"action\": \"List\"\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java Permissions By Resource And Action
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.patch("https://cdn.emnify.net/api/v1/organisation/my/role/12")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"name\": \"Fleet operator v2\",\n  \"permissions\": [\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"List\"\n    },\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"Create\"\n    },\n    {\n      \"resource\": \"ServicePolicy\",\n      \"action\": \"List\"\n    }\n  ]\n}")
  .asString();
```

```php Permissions By Resource And Action
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('PATCH', 'https://cdn.emnify.net/api/v1/organisation/my/role/12', [
  'body' => '{
  "name": "Fleet operator v2",
  "permissions": [
    {
      "resource": "Endpoint",
      "action": "List"
    },
    {
      "resource": "Endpoint",
      "action": "Create"
    },
    {
      "resource": "ServicePolicy",
      "action": "List"
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp Permissions By Resource And Action
using RestSharp;

var client = new RestClient("https://cdn.emnify.net/api/v1/organisation/my/role/12");
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"name\": \"Fleet operator v2\",\n  \"permissions\": [\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"List\"\n    },\n    {\n      \"resource\": \"Endpoint\",\n      \"action\": \"Create\"\n    },\n    {\n      \"resource\": \"ServicePolicy\",\n      \"action\": \"List\"\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Permissions By Resource And Action
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "name": "Fleet operator v2",
  "permissions": [
    [
      "resource": "Endpoint",
      "action": "List"
    ],
    [
      "resource": "Endpoint",
      "action": "Create"
    ],
    [
      "resource": "ServicePolicy",
      "action": "List"
    ]
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://cdn.emnify.net/api/v1/organisation/my/role/12")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "PATCH"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```