> For the complete documentation index, see [llms.txt](https://developers.docstudio.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.docstudio.com/guides/permission-roles.md).

# Permission Roles

This document contains endpoints for creating, retrieving, updating, deleting, and assigning permission roles in DocStudio.

Permission roles combine multiple account or mailbox permissions into reusable access configurations. Instead of granting every permission separately, an organization can create roles for specific responsibilities and assign those roles to users.

A **system role** is predefined by DocStudio and can be reused but not created through the API. A **custom role** belongs to a specific account and contains a user-defined name and permission set.

### Business goals

Permission Role endpoints support the following business goals:

* **Standardize user access.** Create reusable permission sets for users with the same responsibilities.
* **Separate account and mailbox access.** Define roles that apply either to account-level administration or to work within a specific mailbox.
* **Simplify permission management.** Assign a role instead of granting the same permissions separately to multiple users.
* **Retrieve available access configurations.** Find system and custom roles before assigning access to a user.
* **Maintain custom roles.** Create, retrieve, update, or delete roles as organizational responsibilities change.

### Endpoint summary

#### **Role lifecycle**

<table><thead><tr><th width="101.33331298828125">Method</th><th>Endpoint</th><th>Purpose</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>/api/v1/permission/role/{uuid}</code></td><td>Retrieve a role by UUID</td></tr><tr><td><code>POST</code></td><td><code>/api/v1/permission/role</code></td><td>Create a custom role</td></tr><tr><td><code>PUT</code></td><td><code>/api/v1/permission/role/{uuid}</code></td><td>Change the role name and permissions</td></tr><tr><td><code>DELETE</code></td><td><code>/api/v1/permission/role/{uuid}</code></td><td>Delete a custom role</td></tr></tbody></table>

#### **Role discovery**

<table><thead><tr><th width="99.111083984375">Method</th><th width="352">Endpoint</th><th>Purpose</th></tr></thead><tbody><tr><td><code>GET</code></td><td><code>/api/v1/permission/role</code></td><td>Retrieve the predefined system roles</td></tr><tr><td><code>GET</code></td><td><code>/api/v1/permission/role/account/{uuid}</code></td><td>Retrieve system and custom roles available to an account</td></tr></tbody></table>

#### Role structure and headers

Role operations require an API token in the `Authorization` header. Requests that create or update a role must also use `Content-Type: application/json`.

```http
Authorization: Bearer {token}
Content-Type: application/json
```

A role contains the following properties:

<table><thead><tr><th width="129">Property</th><th width="159">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>uuid</code></td><td>UUID</td><td>Unique identifier of the role returned by DocStudio</td></tr><tr><td><code>name</code></td><td>string</td><td>Role name displayed to account administrators</td></tr><tr><td><code>description</code></td><td>string</td><td>Explanation of the responsibilities associated with the role</td></tr><tr><td><code>type</code></td><td>string</td><td>Role context: <code>account</code> or <code>mailbox</code></td></tr><tr><td><code>permissions</code></td><td>array of integers</td><td>Numeric identifiers of the permissions included in the role</td></tr><tr><td><code>accountUuid</code></td><td>UUID</td><td>Account that owns the custom role</td></tr><tr><td><code>system</code></td><td>boolean</td><td>Indicates whether the role is predefined by DocStudio</td></tr></tbody></table>

* An `account` role contains permissions that apply to account-level administration.
* A `mailbox` role contains permissions for working within a mailbox, so its type must correspond to the context in which the role will be assigned.

### Retrieve available roles and permission IDs

Retrieve the predefined system roles before creating a custom role. The response contains each role’s type and the numeric permission IDs included in its `permissions` array.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const url = new URL(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/account/{accountUuid}"
);

url.searchParams.append(
  "permissions",
  "{permissionId1}"
);
url.searchParams.append(
  "permissions",
  "{permissionId2}"
);
url.searchParams.set("offset", "0");
url.searchParams.set("limit", "25");

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: "Bearer {token}"
  }
});

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$baseUrl =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/account/{accountUuid}";

$query = implode("&", [
    "permissions=" . rawurlencode("{permissionId1}"),
    "permissions=" . rawurlencode("{permissionId2}"),
    "offset=0",
    "limit=25"
]);

$curl = curl_init($baseUrl . "?" . $query);

curl_setopt_array($curl, [
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = (
    "https://api.docstudio.com/api/v1/permission/"
    "role/account/{accountUuid}"
)

response = requests.get(
    url,
    headers={
        "Authorization": "Bearer {token}",
    },
    params=[
        ("permissions", "{permissionId1}"),
        ("permissions", "{permissionId2}"),
        ("offset", 0),
        ("limit", 25),
    ],
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/account/{accountUuid}"
)

uri.query = URI.encode_www_form(
  [
    ["permissions", "{permissionId1}"],
    ["permissions", "{permissionId2}"],
    ["offset", 0],
    ["limit", 25]
  ]
)

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	endpoint, err := url.Parse(
		"https://api.docstudio.com/api/v1/permission/" +
			"role/account/{accountUuid}",
	)
	if err != nil {
		panic(err)
	}

	query := endpoint.Query()
	query.Add(
		"permissions",
		"{permissionId1}",
	)
	query.Add(
		"permissions",
		"{permissionId2}",
	)
	query.Set("offset", "0")
	query.Set("limit", "25")
	endpoint.RawQuery = query.Encode()

	request, err := http.NewRequest(
		http.MethodGet,
		endpoint.String(),
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class Main {
  public static void main(String[] args) throws Exception {
    String permissionId1 = URLEncoder.encode(
        "{permissionId1}",
        StandardCharsets.UTF_8
    );

    String permissionId2 = URLEncoder.encode(
        "{permissionId2}",
        StandardCharsets.UTF_8
    );

    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/account/{accountUuid}"
        + "?permissions=" + permissionId1
        + "&permissions=" + permissionId2
        + "&offset=0&limit=25";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .GET()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var permissionId1 =
    Uri.EscapeDataString("{permissionId1}");
var permissionId2 =
    Uri.EscapeDataString("{permissionId2}");

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/account/{accountUuid}" +
    $"?permissions={permissionId1}" +
    $"&permissions={permissionId2}" +
    "&offset=0&limit=25";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request GET \
  --url 'https://api.docstudio.com/api/v1/permission/role/account/{accountUuid}?permissions={permissionId1}&permissions={permissionId2}&offset=0&limit=25' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

Supported query parameters:

<table><thead><tr><th width="122">Parameter</th><th width="149">Type</th><th width="82.5555419921875">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td>string</td><td>No</td><td>Filters roles by <code>account</code> or <code>mailbox</code> type</td></tr><tr><td><code>name</code></td><td>string</td><td>No</td><td>Filters roles by name</td></tr><tr><td><code>permissions</code></td><td>array of integers</td><td>No</td><td>Filters roles by included permission IDs</td></tr><tr><td><code>offset</code></td><td>integer</td><td>No</td><td>Number of roles to skip; the default value is <code>0</code></td></tr><tr><td><code>limit</code></td><td>integer</td><td>No</td><td>Maximum number of roles to return; the default value is <code>25</code></td></tr></tbody></table>

The response is a paginated collection of roles. Use the returned `permissions` arrays to select the permission IDs required for a new custom role.

```json
{
  "totalElements": 1,
  "sizeRequested": 25,
  "numberOfElements": 1,
  "data": [
    {
      "name": "Mailbox Reviewer",
      "description": "Reviews documents in a mailbox",
      "type": "mailbox",
      "permissions": [
        0
      ],
      "accountUuid": "{accountUuid}",
      "system": true,
      "uuid": "{roleUuid}"
    }
  ]
}
```

The `0` permission ID is the generic value used by the Swagger schema. Actual responses contain the numeric permission IDs assigned to the returned roles.

### Practical example: Create and assign a mailbox role

A company wants employees responsible for reviewing contracts to receive the same mailbox permissions. The integration retrieves the available roles, selects the required permission IDs, creates a reusable `Contract Reviewer` role, and assigns it to a user.

#### **Retrieve existing mailbox roles**

Retrieve the roles available to the account and filter the results by the `mailbox` type. Use their `permissions` arrays to identify the permissions required by the new role.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const url = new URL(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/account/{accountUuid}"
);

url.searchParams.set("type", "mailbox");
url.searchParams.set("offset", "0");
url.searchParams.set("limit", "25");

const response = await fetch(url, {
  method: "GET",
  headers: {
    Authorization: "Bearer {token}"
  }
});

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$baseUrl =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/account/{accountUuid}";

$query = http_build_query([
    "type" => "mailbox",
    "offset" => 0,
    "limit" => 25
]);

$curl = curl_init($baseUrl . "?" . $query);

curl_setopt_array($curl, [
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

url = (
    "https://api.docstudio.com/api/v1/permission/"
    "role/account/{accountUuid}"
)

response = requests.get(
    url,
    headers={
        "Authorization": "Bearer {token}",
    },
    params={
        "type": "mailbox",
        "offset": 0,
        "limit": 25,
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/account/{accountUuid}"
)

uri.query = URI.encode_www_form(
  type: "mailbox",
  offset: 0,
  limit: 25
)

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	endpoint, err := url.Parse(
		"https://api.docstudio.com/api/v1/permission/" +
			"role/account/{accountUuid}",
	)
	if err != nil {
		panic(err)
	}

	query := endpoint.Query()
	query.Set("type", "mailbox")
	query.Set("offset", "0")
	query.Set("limit", "25")
	endpoint.RawQuery = query.Encode()

	request, err := http.NewRequest(
		http.MethodGet,
		endpoint.String(),
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/account/{accountUuid}"
        + "?type=mailbox&offset=0&limit=25";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .GET()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/account/{accountUuid}" +
    "?type=mailbox&offset=0&limit=25";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request GET \
  --url 'https://api.docstudio.com/api/v1/permission/role/account/{accountUuid}?type=mailbox&offset=0&limit=25' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

#### **Create the custom role**

Send the selected numeric permission IDs in the `permissions` array. The role type is `mailbox` because it will be assigned within a mailbox.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/role",
  {
    method: "POST",
    headers: {
      Authorization: "Bearer {token}",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      name: "Contract Reviewer",
      description:
        "Reviews contracts received by the mailbox",
      type: "mailbox",
      permissions: [0],
      accountUuid: "{accountUuid}",
      system: false
    })
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$payload = json_encode([
    "name" => "Contract Reviewer",
    "description" =>
        "Reviews contracts received by the mailbox",
    "type" => "mailbox",
    "permissions" => [0],
    "accountUuid" => "{accountUuid}",
    "system" => false
], JSON_THROW_ON_ERROR);

$curl = curl_init(
    "https://api.docstudio.com/api/v1/permission/role"
);

curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.post(
    "https://api.docstudio.com/api/v1/permission/role",
    headers={
        "Authorization": "Bearer {token}",
    },
    json={
        "name": "Contract Reviewer",
        "description": (
            "Reviews contracts received by the mailbox"
        ),
        "type": "mailbox",
        "permissions": [0],
        "accountUuid": "{accountUuid}",
        "system": False,
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "json"
require "net/http"
require "uri"

payload = {
  name: "Contract Reviewer",
  description:
    "Reviews contracts received by the mailbox",
  type: "mailbox",
  permissions: [0],
  accountUuid: "{accountUuid}",
  system: false
}

uri = URI(
  "https://api.docstudio.com/api/v1/permission/role"
)

request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer {token}"
request["Content-Type"] = "application/json"
request.body = JSON.generate(payload)

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	payload := map[string]any{
		"name": "Contract Reviewer",
		"description":
			"Reviews contracts received by the mailbox",
		"type":        "mailbox",
		"permissions": []int{0},
		"accountUuid": "{accountUuid}",
		"system":      false,
	}

	requestBody, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	request, err := http.NewRequest(
		http.MethodPost,
		"https://api.docstudio.com/api/v1/permission/role",
		bytes.NewReader(requestBody),
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)
	request.Header.Set(
		"Content-Type",
		"application/json",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String payload = """
        {
          "name": "Contract Reviewer",
          "description": "Reviews contracts received by the mailbox",
          "type": "mailbox",
          "permissions": [
            0
          ],
          "accountUuid": "{accountUuid}",
          "system": false
        }
        """;

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(
            "https://api.docstudio.com/api/v1/permission/role"
        ))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .header(
            "Content-Type",
            "application/json"
        )
        .POST(
            HttpRequest.BodyPublishers.ofString(payload)
        )
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var payload = JsonSerializer.Serialize(new
{
    name = "Contract Reviewer",
    description =
        "Reviews contracts received by the mailbox",
    type = "mailbox",
    permissions = new[] { 0 },
    accountUuid = "{accountUuid}",
    system = false
});

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://api.docstudio.com/api/v1/permission/role"
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

request.Content = new StringContent(
    payload,
    Encoding.UTF8,
    "application/json"
);

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request POST \
  --url 'https://api.docstudio.com/api/v1/permission/role' \
  --header 'Authorization: Bearer {token}' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Contract Reviewer",
    "description": "Reviews contracts received by the mailbox",
    "type": "mailbox",
    "permissions": [
      0
    ],
    "accountUuid": "{accountUuid}",
    "system": false
  }'
```

{% endtab %}
{% endtabs %}

Replace `0` with an actual permission ID returned by the role discovery endpoints. Include every permission that users assigned to this role must receive.

A successful request returns `201 Created` and the created role object. Save the returned `uuid` because it identifies the role in subsequent read, update, delete, and assignment operations.

```json
{
  "name": "Contract Reviewer",
  "description": "Reviews contracts received by the mailbox",
  "type": "mailbox",
  "permissions": [
    0
  ],
  "accountUuid": "{accountUuid}",
  "system": false,
  "uuid": "{roleUuid}"
}
```

#### **Retrieve the created role**

Use the returned `roleUuid` to verify the stored role configuration. The response contains the current name, description, type, permissions, account UUID, system-role indicator, and role UUID.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/{roleUuid}",
  {
    method: "GET",
    headers: {
      Authorization: "Bearer {token}"
    }
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/{roleUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.get(
    "https://api.docstudio.com/api/v1/permission/"
    "role/{roleUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/{roleUuid}"
)

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	url := "https://api.docstudio.com/api/v1/permission/" +
		"role/{roleUuid}"

	request, err := http.NewRequest(
		http.MethodGet,
		url,
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/{roleUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .GET()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/{roleUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request GET \
  --url 'https://api.docstudio.com/api/v1/permission/role/{roleUuid}' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

#### **Assign the role to a user**

Use the mailbox permission endpoint to assign the created role to a user. Send its UUID in the `roles` array and leave `permissions` empty when no individual permissions need to be added.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "{userUuid}/mailbox/{mailboxUuid}",
  {
    method: "PATCH",
    headers: {
      Authorization: "Bearer {token}",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      permissions: [],
      roles: ["{roleUuid}"]
    })
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

if (body) {
  console.log(body);
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$payload = json_encode([
    "permissions" => [],
    "roles" => [
        "{roleUuid}"
    ]
], JSON_THROW_ON_ERROR);

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "{userUuid}/mailbox/{mailboxUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

if ($body !== "") {
    echo $body;
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.patch(
    "https://api.docstudio.com/api/v1/permission/"
    "{userUuid}/mailbox/{mailboxUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    json={
        "permissions": [],
        "roles": [
            "{roleUuid}",
        ],
    },
    timeout=30,
)

response.raise_for_status()

if response.text:
    print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "json"
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "{userUuid}/mailbox/{mailboxUuid}"
)

payload = {
  permissions: [],
  roles: [
    "{roleUuid}"
  ]
}

request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer {token}"
request["Content-Type"] = "application/json"
request.body = JSON.generate(payload)

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body unless response.body.empty?
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	payload := map[string]any{
		"permissions": []int{},
		"roles": []string{
			"{roleUuid}",
		},
	}

	requestBody, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	url := "https://api.docstudio.com/api/v1/permission/" +
		"{userUuid}/mailbox/{mailboxUuid}"

	request, err := http.NewRequest(
		http.MethodPatch,
		url,
		bytes.NewReader(requestBody),
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)
	request.Header.Set(
		"Content-Type",
		"application/json",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	if len(body) > 0 {
		fmt.Println(string(body))
	}
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String payload = """
        {
          "permissions": [],
          "roles": [
            "{roleUuid}"
          ]
        }
        """;

    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "{userUuid}/mailbox/{mailboxUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .header(
            "Content-Type",
            "application/json"
        )
        .method(
            "PATCH",
            HttpRequest.BodyPublishers.ofString(payload)
        )
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    if (!response.body().isEmpty()) {
      System.out.println(response.body());
    }
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var payload = JsonSerializer.Serialize(new
{
    permissions = Array.Empty<int>(),
    roles = new[]
    {
        "{roleUuid}"
    }
});

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "{userUuid}/mailbox/{mailboxUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    new HttpMethod("PATCH"),
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

request.Content = new StringContent(
    payload,
    Encoding.UTF8,
    "application/json"
);

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

if (!string.IsNullOrEmpty(body))
{
    Console.WriteLine(body);
}
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request PATCH \
  --url 'https://api.docstudio.com/api/v1/permission/{userUuid}/mailbox/{mailboxUuid}' \
  --header 'Authorization: Bearer {token}' \
  --header 'Content-Type: application/json' \
  --data '{
    "permissions": [],
    "roles": [
      "{roleUuid}"
    ]
  }'
```

{% endtab %}
{% endtabs %}

The `PATCH` request adds the role without removing the user’s existing mailbox permissions or roles. If the custom role has the `account` type, assign it through the corresponding account permission endpoint.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "{userUuid}/account/{accountUuid}",
  {
    method: "PATCH",
    headers: {
      Authorization: "Bearer {token}",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      permissions: [],
      roles: ["{roleUuid}"]
    })
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

if (body) {
  console.log(body);
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$payload = json_encode([
    "permissions" => [],
    "roles" => [
        "{roleUuid}"
    ]
], JSON_THROW_ON_ERROR);

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "{userUuid}/account/{accountUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => "PATCH",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

if ($body !== "") {
    echo $body;
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.patch(
    "https://api.docstudio.com/api/v1/permission/"
    "{userUuid}/account/{accountUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    json={
        "permissions": [],
        "roles": [
            "{roleUuid}",
        ],
    },
    timeout=30,
)

response.raise_for_status()

if response.text:
    print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "json"
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "{userUuid}/account/{accountUuid}"
)

payload = {
  permissions: [],
  roles: [
    "{roleUuid}"
  ]
}

request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer {token}"
request["Content-Type"] = "application/json"
request.body = JSON.generate(payload)

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body unless response.body.empty?
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	payload := map[string]any{
		"permissions": []int{},
		"roles": []string{
			"{roleUuid}",
		},
	}

	requestBody, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	url := "https://api.docstudio.com/api/v1/permission/" +
		"{userUuid}/account/{accountUuid}"

	request, err := http.NewRequest(
		http.MethodPatch,
		url,
		bytes.NewReader(requestBody),
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)
	request.Header.Set(
		"Content-Type",
		"application/json",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	if len(body) > 0 {
		fmt.Println(string(body))
	}
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String payload = """
        {
          "permissions": [],
          "roles": [
            "{roleUuid}"
          ]
        }
        """;

    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "{userUuid}/account/{accountUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .header(
            "Content-Type",
            "application/json"
        )
        .method(
            "PATCH",
            HttpRequest.BodyPublishers.ofString(payload)
        )
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    if (!response.body().isEmpty()) {
      System.out.println(response.body());
    }
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var payload = JsonSerializer.Serialize(new
{
    permissions = Array.Empty<int>(),
    roles = new[]
    {
        "{roleUuid}"
    }
});

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "{userUuid}/account/{accountUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    new HttpMethod("PATCH"),
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

request.Content = new StringContent(
    payload,
    Encoding.UTF8,
    "application/json"
);

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

if (!string.IsNullOrEmpty(body))
{
    Console.WriteLine(body);
}
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request PATCH \
  --url 'https://api.docstudio.com/api/v1/permission/{userUuid}/account/{accountUuid}' \
  --header 'Authorization: Bearer {token}' \
  --header 'Content-Type: application/json' \
  --data '{
    "permissions": [],
    "roles": [
      "{roleUuid}"
    ]
  }'
```

{% endtab %}
{% endtabs %}

Use `PUT` instead of `PATCH` only when the complete set of permissions and roles must be replaced. A `PUT` request overwrites the user’s existing assignments in the selected account or mailbox context.

{% hint style="warning" %}
Use `PATCH` to add a role without removing existing assignments. Use `PUT` only when the complete permission and role configuration must be replaced.
{% endhint %}

### Practical example: Update an existing custom role

An organization has expanded the responsibilities of its `Contract Reviewer` role. The integration retrieves the role, updates its name and permission set, and then retrieves it again to confirm the resulting configuration.

#### **Retrieve the current role**

Retrieve the role before preparing the update. Preserve the required role properties and identify the permission IDs that must be added or removed.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/{roleUuid}",
  {
    method: "GET",
    headers: {
      Authorization: "Bearer {token}"
    }
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/{roleUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.get(
    "https://api.docstudio.com/api/v1/permission/"
    "role/{roleUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/{roleUuid}"
)

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	url := "https://api.docstudio.com/api/v1/permission/" +
		"role/{roleUuid}"

	request, err := http.NewRequest(
		http.MethodGet,
		url,
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/{roleUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .GET()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/{roleUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request GET \
  --url 'https://api.docstudio.com/api/v1/permission/role/{roleUuid}' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

#### **Update the role**

Send the complete updated role object and replace the generic permission values with the required numeric IDs. The endpoint allows the role name and permission set to be changed.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/{roleUuid}",
  {
    method: "PUT",
    headers: {
      Authorization: "Bearer {token}",
      "Content-Type": "application/json"
    },
    body: JSON.stringify({
      name: "Senior Contract Reviewer",
      description:
        "Reviews contracts received by the mailbox",
      type: "mailbox",
      permissions: [0],
      accountUuid: "{accountUuid}",
      system: false
    })
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$payload = json_encode([
    "name" => "Senior Contract Reviewer",
    "description" =>
        "Reviews contracts received by the mailbox",
    "type" => "mailbox",
    "permissions" => [0],
    "accountUuid" => "{accountUuid}",
    "system" => false
], JSON_THROW_ON_ERROR);

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/{roleUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => "PUT",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}",
        "Content-Type: application/json"
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.put(
    "https://api.docstudio.com/api/v1/permission/"
    "role/{roleUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    json={
        "name": "Senior Contract Reviewer",
        "description": (
            "Reviews contracts received by the mailbox"
        ),
        "type": "mailbox",
        "permissions": [0],
        "accountUuid": "{accountUuid}",
        "system": False,
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "json"
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/{roleUuid}"
)

payload = {
  name: "Senior Contract Reviewer",
  description:
    "Reviews contracts received by the mailbox",
  type: "mailbox",
  permissions: [0],
  accountUuid: "{accountUuid}",
  system: false
}

request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer {token}"
request["Content-Type"] = "application/json"
request.body = JSON.generate(payload)

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	payload := map[string]any{
		"name": "Senior Contract Reviewer",
		"description":
			"Reviews contracts received by the mailbox",
		"type":        "mailbox",
		"permissions": []int{0},
		"accountUuid": "{accountUuid}",
		"system":      false,
	}

	requestBody, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	url := "https://api.docstudio.com/api/v1/permission/" +
		"role/{roleUuid}"

	request, err := http.NewRequest(
		http.MethodPut,
		url,
		bytes.NewReader(requestBody),
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)
	request.Header.Set(
		"Content-Type",
		"application/json",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String payload = """
        {
          "name": "Senior Contract Reviewer",
          "description": "Reviews contracts received by the mailbox",
          "type": "mailbox",
          "permissions": [
            0
          ],
          "accountUuid": "{accountUuid}",
          "system": false
        }
        """;

    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/{roleUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .header(
            "Content-Type",
            "application/json"
        )
        .PUT(
            HttpRequest.BodyPublishers.ofString(payload)
        )
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var payload = JsonSerializer.Serialize(new
{
    name = "Senior Contract Reviewer",
    description =
        "Reviews contracts received by the mailbox",
    type = "mailbox",
    permissions = new[] { 0 },
    accountUuid = "{accountUuid}",
    system = false
});

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/{roleUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Put,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

request.Content = new StringContent(
    payload,
    Encoding.UTF8,
    "application/json"
);

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request PUT \
  --url 'https://api.docstudio.com/api/v1/permission/role/{roleUuid}' \
  --header 'Authorization: Bearer {token}' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Senior Contract Reviewer",
    "description": "Reviews contracts received by the mailbox",
    "type": "mailbox",
    "permissions": [
      0
    ],
    "accountUuid": "{accountUuid}",
    "system": false
  }'
```

{% endtab %}
{% endtabs %}

A successful request returns `200 OK` and the updated role object. Retrieve the role again if the integration needs to verify its final configuration before assigning it to additional users.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/{roleUuid}",
  {
    method: "GET",
    headers: {
      Authorization: "Bearer {token}"
    }
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

console.log(body);
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/{roleUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_HTTPGET => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

echo $body;
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.get(
    "https://api.docstudio.com/api/v1/permission/"
    "role/{roleUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    timeout=30,
)

response.raise_for_status()
print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/{roleUuid}"
)

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	url := "https://api.docstudio.com/api/v1/permission/" +
		"role/{roleUuid}"

	request, err := http.NewRequest(
		http.MethodGet,
		url,
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/{roleUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .GET()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    System.out.println(response.body());
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/{roleUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Get,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

Console.WriteLine(body);
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request GET \
  --url 'https://api.docstudio.com/api/v1/permission/role/{roleUuid}' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

### Delete a custom role

Delete a custom role when it is no longer required. Use the role UUID returned when the role was created or retrieved.

{% tabs %}
{% tab title="Node.js" %}

```javascript
const response = await fetch(
  "https://api.docstudio.com/api/v1/permission/" +
  "role/{roleUuid}",
  {
    method: "DELETE",
    headers: {
      Authorization: "Bearer {token}"
    }
  }
);

const body = await response.text();

if (!response.ok) {
  throw new Error(
    `Request failed: ${response.status}\n${body}`
  );
}

if (body) {
  console.log(body);
}
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$url =
    "https://api.docstudio.com/api/v1/permission/" .
    "role/{roleUuid}";

$curl = curl_init($url);

curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer {token}"
    ],
    CURLOPT_RETURNTRANSFER => true
]);

$body = curl_exec($curl);

if ($body === false) {
    throw new RuntimeException(curl_error($curl));
}

$status = curl_getinfo($curl, CURLINFO_RESPONSE_CODE);
curl_close($curl);

if ($status < 200 || $status >= 300) {
    throw new RuntimeException(
        "Request failed: {$status}\n{$body}"
    );
}

if ($body !== "") {
    echo $body;
}
```

{% endtab %}

{% tab title="Python" %}

```python
import requests

response = requests.delete(
    "https://api.docstudio.com/api/v1/permission/"
    "role/{roleUuid}",
    headers={
        "Authorization": "Bearer {token}",
    },
    timeout=30,
)

response.raise_for_status()

if response.text:
    print(response.text)
```

{% endtab %}

{% tab title="Ruby" %}

```ruby
require "net/http"
require "uri"

uri = URI(
  "https://api.docstudio.com/api/v1/permission/" \
  "role/{roleUuid}"
)

request = Net::HTTP::Delete.new(uri)
request["Authorization"] = "Bearer {token}"

response = Net::HTTP.start(
  uri.hostname,
  uri.port,
  use_ssl: uri.scheme == "https"
) do |http|
  http.request(request)
end

unless response.is_a?(Net::HTTPSuccess)
  raise "Request failed: #{response.code}\n#{response.body}"
end

puts response.body unless response.body.empty?
```

{% endtab %}

{% tab title="Go" %}

```go
package main

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

func main() {
	url := "https://api.docstudio.com/api/v1/permission/" +
		"role/{roleUuid}"

	request, err := http.NewRequest(
		http.MethodDelete,
		url,
		nil,
	)
	if err != nil {
		panic(err)
	}

	request.Header.Set(
		"Authorization",
		"Bearer {token}",
	)

	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()

	body, err := io.ReadAll(response.Body)
	if err != nil {
		panic(err)
	}

	if response.StatusCode < 200 ||
		response.StatusCode >= 300 {
		panic(fmt.Sprintf(
			"Request failed: %s\n%s",
			response.Status,
			body,
		))
	}

	if len(body) > 0 {
		fmt.Println(string(body))
	}
}
```

{% endtab %}

{% tab title="Java" %}

```java
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
  public static void main(String[] args) throws Exception {
    String url =
        "https://api.docstudio.com/api/v1/permission/"
        + "role/{roleUuid}";

    HttpRequest request = HttpRequest.newBuilder()
        .uri(URI.create(url))
        .header(
            "Authorization",
            "Bearer {token}"
        )
        .DELETE()
        .build();

    HttpResponse<String> response =
        HttpClient.newHttpClient().send(
            request,
            HttpResponse.BodyHandlers.ofString()
        );

    if (response.statusCode() < 200 ||
        response.statusCode() >= 300) {
      throw new RuntimeException(
          "Request failed: " + response.statusCode()
          + "\n" + response.body()
      );
    }

    if (!response.body().isEmpty()) {
      System.out.println(response.body());
    }
  }
}
```

{% endtab %}

{% tab title=".NET" %}

```csharp
using System;
using System.Net.Http;
using System.Net.Http.Headers;

var url =
    "https://api.docstudio.com/api/v1/permission/" +
    "role/{roleUuid}";

using var client = new HttpClient();

using var request = new HttpRequestMessage(
    HttpMethod.Delete,
    url
);

request.Headers.Authorization =
    new AuthenticationHeaderValue("Bearer", "{token}");

using var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();

if (!response.IsSuccessStatusCode)
{
    throw new HttpRequestException(
        $"Request failed: {(int)response.StatusCode}\n{body}"
    );
}

if (!string.IsNullOrEmpty(body))
{
    Console.WriteLine(body);
}
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl --request DELETE \
  --url 'https://api.docstudio.com/api/v1/permission/role/{roleUuid}' \
  --header 'Authorization: Bearer {token}'
```

{% endtab %}
{% endtabs %}

A successful request returns `204 No Content` without a response body. Remove or replace the role in existing user permission configurations when necessary.

### Related topics

* [Authorization](/api-reference/authorization.md)
* [Error handling and API error codes](/error-codes/error-handling-and-api-error-codes.md)
