Important: Relationship-based access control is in early access. This API is subject to change and should not be used in a production environment.

You can customize the authorization of requests by implementing policies. Every legacy object type and legacy relationship type has a policy to define role-based access control (RBAC). Every legacy object type has zero or more policies to define relationship-based access control (ReBAC).

The RBAC policy on a legacy object type or relationship type grants create, read, update, and delete permissions to agents and end users for object records or relationship records of that type. If you provision agent and end user RBAC read permission, then they can read the type as well.

A ReBAC policy on a legacy object type ot grants additional read and update permissions to agents and end users. Each ReBAC policy specifies a relationship type with a source object type of zen:user and a target object type of ot. If an existing legacy relationship record of that type points from the user making the request to a legacy object record of type ot, then the ReBAC policy grants read and update permissions to the object record. In other words, the RBAC policy on the object type might forbid an agent or end user from reading or updating legacy object records of that type, but a ReBAC policy on the legacy object type can allow the user to read or update specific object records of the type.

JSON format

Permissions are represented as JSON objects with the following properties:

NameTypeRead-onlyMandatoryDescription
rbacobjectfalsefalseThe RBAC policy for the object type
rebacobjectfalsefalse

Relationship type policies are defined by a JSON object with the following properties:

NameTypeWritableRequiredComment
rbacobjectyesyesThe RBAC policy for the relationship type

An RBAC policy consists of a JSON object with the following properties:

NameTypeWritableRequiredComment
adminobjectyesnoThe CRUD permission definition for admins
agentobjectyesnoThe CRUD permission definition for agents
end_userobjectyesnoThe CRUD permission definition for end users
customobjectyesnoThe CRUD permission definitions for custom agent roles. In this object, each property maps a custom agent role to a CRUD permission definition.

A ReBAC policy consists of a JSON object with the following properties:

NameTypeWritableRequiredComment
adminobjectyesnoThe RU (read/update) permission definition for admins
agentobjectyesnoThe RU permission definition for agents
end_userobjectyesnoThe RU permission definition for end users
customobjectyesnoThe RU permission definitions for custom agent roles. In this object, each property maps a custom agent role to an RU permission definition.

A CRUD permission definition consists of a JSON object with the following properties:

NameTypeWritableRequiredComment
createbooleanyesno
readbooleanyesno
updatebooleanyesno
deletebooleanyesno

An RU (read/update) permission definition consists of a JSON object with the following properties:

NameTypeWritableRequiredComment
readbooleanyesno
updatebooleanyesno

Policies for custom agent roles

On the Enterprise plan, admins can define custom agent roles and assign those roles to any agent. See Creating custom roles and assigning agents (Enterprise) in Help Center.

An RBAC or ReBAC policy can have a legacy custom object that defines the permissions of an agent with a custom agent role. The object specifies the ID of the custom role and a permissions policy, which can either be a CRUD or a RU policy depending on whether the parent is RBAC or ReBAC, respectively.

You can get the id of the custom role using the List Custom Roles endpoint. Custom role IDs are not validated to see if roles exist for them.

If any permission value is left unspecified (create, read, update or delete for a CRUD permission definition, and read or update for an RU permission definition) within a custom agent role policy, the unspecified values will be populated with the value false.

If a request is made by a user with a custom agent role, but no policy has been created for that custom agent role, the request will be handled with the existing agent permissions for the object or relationship type that is the subject of the request.

If a request is made by a user with a custom agent role and a policy exists for that custom role, that policy will override the normal agent permissions granted to the user.

Example

{  "data": {    "rbac": {      "agent": {        "create": true,        "read": true,        "update": false,        "delete": false      },      "custom": {        "8237": {          "create": false,          "read": true,          "update": true,          "delete": false        }      }    },    "rebac": {      "user_to_many_products": {        "end_user": {          "update": true        },        "custom": {          "8237": {            "read": true,            "update": false          }        }      }    }  }}

Default role-based access control (RBAC) policy

When a legacy object type or relationship type is created, a default RBAC policy is issued to the type. The default RBAC policy is used to enforce the authorization rules for any incoming requests on legacy object records or relationship records associated with the legacy object type or relationship type. The permissions defined in the default RBAC policy are as follows.

{  "admin": {    "create": true,    "read": true,    "update": true,    "delete": true  },  "agent": {    "create": true,    "read": true,    "update": true,    "delete": true  },  "end_user": {    "create": false,    "read": false,    "update": false,    "delete": false  }}

Default relationship-based access control (ReBAC) policy

When a ReBAC policy is created on a legacy object type, not all permissions need to be specified. If the definition omits some permissions, then their default values are as follows.

{  "admin": {    "read": true,    "update": true  },  "agent": {    "read": false,    "update": false  },  "end_user": {    "read": false,    "update": false  }}

A final full example with all properties.

Example

{  "rbac": {    "agent": {      "create": true,      "delete": false,      "read": true,      "update": true    },    "custom": {      "8237": {        "create": false,        "delete": false,        "read": true,        "update": true      }    },    "end_user": {      "read": true    }  },  "rebac": {    "user_to_many_products": {      "custom": {        "8237": {          "read": true,          "update": true        }      },      "end_user": {        "update": true      }    }  }}

Show Legacy Object Type Policies

  • GET /api/sunshine/objects/types/{object_type_key}/permissions

Returns the policies for the specified legacy object type.

Allowed for

  • Agents

Parameters

NameTypeInRequiredDescription
object_type_keystringPathtrueThe key property is a unique identifier for the legacy object type that you define yourself

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/sunshine/objects/types/{object_type_key}/permissions \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/objects/types/product/permissions"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/objects/types/product/permissions")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://support.zendesk.com/api/sunshine/objects/types/product/permissions',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/objects/types/product/permissions"headers = {	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/objects/types/product/permissions")request = Net::HTTP::Get.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": {    "rbac": {      "admin": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "agent": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "end_user": {        "create": false,        "delete": false,        "read": false,        "update": false      }    }  }}

Update Legacy Object Type Policies

  • PATCH /api/sunshine/objects/types/{object_type_key}/permissions

Updates the policies for the specified legacy object type. If no updates to the RBAC policy have occurred, then the default RBAC policy is used. If a request creates a new ReBAC policy for a legacy object type and a property is omitted from the ReBAC policy, then the corresponding property from the default ReBAC policy is used. If a request updates an existing RBAC policy or ReBAC policy and a property is omitted, then the corresponding property from the previous policy is used.

Allowed for

  • Admins

Parameters

NameTypeInRequiredDescription
object_type_keystringPathtrueThe key property is a unique identifier for the legacy object type that you define yourself

Code Samples

curl

For clarity, the example places the JSON in a separate file and imports it into the cURL statement.

policies.json

{  "data": {    "rbac": {      "agent": {        "create": true,        "read": true,        "update": true,        "delete": false      },      "end_user": {        "read": true      }    },    "rebac": {      "user_to_many_products": {        "end_user": {          "update": true        }      }    }  }}

curl snippet

curl https://{subdomain}.zendesk.com/api/sunshine/objects/types/{object_type_key}/permissions \  -d @policies.json \  -H "Content-Type: application/merge-patch+json" -X PATCH \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/objects/types/product/permissions"	method := "PATCH"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/objects/types/product/permissions")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("PATCH", body)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'PATCH',  url: 'https://support.zendesk.com/api/sunshine/objects/types/product/permissions',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/objects/types/product/permissions"headers = {	"Content-Type": "application/json",}
response = requests.request(	"PATCH",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/objects/types/product/permissions")request = Net::HTTP::Patch.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": {    "rbac": {      "admin": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "agent": {        "create": true,        "delete": false,        "read": true,        "update": true      },      "end_user": {        "create": false,        "delete": false,        "read": true,        "update": false      }    },    "rebac": {      "user_to_many_products": {        "admin": {          "read": true,          "update": true        },        "agent": {          "read": false,          "update": false        },        "end_user": {          "read": false,          "update": true        }      }    }  }}

Show Legacy Relationship Type Policies

  • GET /api/sunshine/relationships/types/{relationship_type_key}/permissions

Returns the policies for the specified legacy relationship type.

Allowed for

  • Agents

Parameters

NameTypeInRequiredDescription
relationship_type_keystringPathtrueThe key of the legacy relationship type

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/sunshine/relationships/types/{relationship_type_key}/permissions \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions"headers = {	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions")request = Net::HTTP::Get.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": {    "rbac": {      "admin": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "agent": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "end_user": {        "create": false,        "delete": false,        "read": false,        "update": false      }    }  }}

Update Legacy Relationship Type Policies

  • PATCH /api/sunshine/relationships/types/{relationship_type_key}/permissions

Updates the policies for the specified legacy relationship type. If no updates to the RBAC policy have occurred, then the default RBAC policy is used. ReBAC policies cannot be created for legacy relationship types. If a request updates an existing RBAC policy or ReBAC policy and a property is omitted, then the corresponding property from the previous policy is used.

Allowed for

  • Admins

Parameters

NameTypeInRequiredDescription
relationship_type_keystringPathtrueThe key of the legacy relationship type

Code Samples

curl

For clarity, the example places the JSON in a separate file and imports it into the cURL statement.

policies.json

{  "data": {    "rbac": {      "agent": {        "create": true,        "read": true,        "update": true,        "delete": false      },      "end_user": {        "read": true      }    }  }}

curl snippet

curl https://{subdomain}.zendesk.com/api/sunshine/relationships/types/{relationship_type_key}/permissions \  -d @policies.json \  -H "Content-Type: application/merge-patch+json" -X PATCH \  -v -u {email_address}/token:{api_token}
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions"	method := "PATCH"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Content-Type", "application/json")
	client := &http.Client {}	res, err := client.Do(req)	if err != nil {		fmt.Println(err)		return	}	defer res.Body.Close()
	body, err := io.ReadAll(res.Body)	if err != nil {		fmt.Println(err)		return	}	fmt.Println(string(body))}
Java
import com.squareup.okhttp.*;OkHttpClient client = new OkHttpClient();HttpUrl.Builder urlBuilder = HttpUrl.parse("https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("PATCH", body)		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'PATCH',  url: 'https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions',  headers: {	'Content-Type': 'application/json',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions"headers = {	"Content-Type": "application/json",}
response = requests.request(	"PATCH",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://support.zendesk.com/api/sunshine/relationships/types/suppliers/permissions")request = Net::HTTP::Patch.new(uri, "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

200 OK
// Status 200 OK
{  "data": {    "rbac": {      "admin": {        "create": true,        "delete": true,        "read": true,        "update": true      },      "agent": {        "create": true,        "delete": false,        "read": true,        "update": true      },      "end_user": {        "create": false,        "delete": false,        "read": true,        "update": false      }    },    "rebac": {}  }}