Approvals are requests that agents create and assign to other agents, agent groups, or end users for review and decision-making.

For more information, see Understanding approvals and how they work.

JSON format

Approval Requests are represented as JSON objects with the following properties:

NameTypeRead-onlyMandatoryDescription
approval_workflow_instance_idstringtruefalseUnique identifier (ULID) of the parent workflow instance. Approval requests created together as a parallel group share the same value.
assignee_group_idintegerfalsefalseThe id of the group assigned to review the request
assignee_user_idintegerfalsefalseThe id of the user assigned to respond to the request. Also referred to as the approver
created_atstringtruefalseThe ISO 8601 formatted date-time when the approval request was created
created_by_idintegertruefalseThe id of the user who created the approval request
idstringtruefalseUnique identifier for the approval request (ULID format)
messagestringfalsefalseDetails and context for the approval request
origination_typestringtruefalseHow the approval request was created. Allowed values are "API_ORIGINATION", "UI_ORIGINATION", "TRIGGER_ORIGINATION", "DATA_IMPORTER_ORIGINATION", "TEMPLATE_ORIGINATION", "ACTION_FLOW_ORIGINATION", or "UNKNOWN_ORIGINATION".
statusstringtruefalseCurrent status of the approval request
subjectstringfalsefalseSubject line for the approval request
ticket_idintegerfalsefalseThe id of the ticket this approval request is attached to

List Approval Requests

  • GET /api/v2/approval_requests

Lists all approval requests for the current account with optional filtering by status and assignee.

Allowed For

  • Admins

Query Parameters

NameTypeDescription
filter[status]stringFilter by a comma-separated list of one or more approval statuses. Values: active, approved, rejected, withdrawn. Case-insensitive
filter[assignee_user_id]stringFilter by a comma-separated list of assigned user ids. Maximum 100 ids
filter[assignee_group_id]stringFilter by a comma-separated list of assigned group ids. Maximum 100 ids
includestringComma-separated list of extra fields to sideload. Supports deeplinks — adds a deeplink field to each approval request, resolving to that request's agent-facing or Help Center decision page. Omitting include leaves the response unchanged.

include=deeplinks requires the approvals_api_parity feature to be enabled for the account. When it isn't, include=deeplinks is silently ignored: no deeplink field is added, and the rest of the response is unaffected.

Filtering Logic

  • When multiple values are provided for a filter, or logic is used. For example, filter[status]=active,approved is evaluated as status=active OR status=approved.
  • If multiple filters are applied to a single request, AND logic is used. For example, filter[status]=active AND filter[assignee_user_id]=123.
  • Each filter parameter supports a maximum 100 values.
  • Numeric ids must be valid integers.

Pagination

This endpoint supports cursor-based pagination. Use after_cursor and before_cursor parameters to navigate through results.

Parameters

NameTypeInRequiredDescription
after_cursorstringQueryfalseCursor for pagination. Fetch records after this cursor
before_cursorstringQueryfalseCursor for pagination. Fetch records before this cursor
filter[assignee_group_id]stringQueryfalseFilter by a comma-separated list of assigned group ids. Maximum 100 ids.
filter[assignee_user_id]stringQueryfalseFilter by a comma-separated list of assigned user ids. Maximum 100 ids.
filter[status]stringQueryfalseFilter by a comma-separated list of one or more approval statuses. Allowed values are active, approved, rejected, withdrawn. Case-insensitive. Maximum 100 values.
includestringQueryfalseComma-separated list of extra fields to sideload. Supports deeplinks — adds a deeplink field to each approval request. Requires the approvals_api_parity feature; silently ignored when the account doesn't have it enabled.

Code Samples

curl
curl -H "Authorization: Bearer {access_token}" https://{subdomain}.zendesk.com/api/v2/approval_requests \  -H "Content-Type: application/json"
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/approval_requests?after_cursor=&before_cursor=&filter[assignee_group_id]=&filter[assignee_user_id]=&filter[status]=&include=deeplinks"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_requests")		.newBuilder()		.addQueryParameter("after_cursor", "")		.addQueryParameter("before_cursor", "")		.addQueryParameter("filter[assignee_group_id]", "")		.addQueryParameter("filter[assignee_user_id]", "")		.addQueryParameter("filter[status]", "")		.addQueryParameter("include", "deeplinks");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://example.zendesk.com/api/v2/approval_requests',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  params: {    'after_cursor': '',    'before_cursor': '',    'filter[assignee_group_id]': '',    'filter[assignee_user_id]': '',    'filter[status]': '',    'include': 'deeplinks',  },};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requests
url = "https://example.zendesk.com/api/v2/approval_requests?after_cursor=&before_cursor=&filter[assignee_group_id]=&filter[assignee_user_id]=&filter[status]=&include=deeplinks"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_requests")uri.query = URI.encode_www_form("after_cursor": "", "before_cursor": "", "filter[assignee_group_id]": "", "filter[assignee_user_id]": "", "filter[status]": "", "include": "deeplinks")request = Net::HTTP::Get.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end
curl with single filter
curl "https://{subdomain}.zendesk.com/api/v2/approval_requests?filter[status]=active&filter[assignee_user_id]=12345" \  -v -H "Authorization: Bearer {access_token}"
curl with multiple filter values
curl "https://{subdomain}.zendesk.com/api/v2/approval_requests?filter[status]=active,approved&filter[assignee_user_id]=123,456" \  -v -H "Authorization: Bearer {access_token}"
curl with deep links
curl "https://{subdomain}.zendesk.com/api/v2/approval_requests?include=deeplinks" \  -v -H "Authorization: Bearer {access_token}"

Example response(s)

200 OK
// Status 200 OK
{  "approval_requests": [    {      "approval_workflow_instance_id": "01HX123ABD",      "assignee_user": {        "id": 12345,        "name": "Jane Approver"      },      "clarification_flow_messages": [],      "created_at": "2025-02-26T10:30:00Z",      "created_by_user": {        "id": 789,        "name": "John Requester",        "photo": {          "content_url": "https://example.zendesk.com/photos/789.jpg"        }      },      "decided_at": null,      "decisions": [],      "id": "01HX123ABC",      "message": "Please approve the software license request",      "origination_type": "API_ORIGINATION",      "status": "active",      "subject": "Software License Approval",      "ticket_id": 101,      "withdrawn_reason": null    },    {      "approval_workflow_instance_id": "01HX123DEG",      "assignee_group": {        "id": 456,        "name": "Approval Team"      },      "clarification_flow_messages": [        {          "author": {            "avatar": "https://example.zendesk.com/avatars/999.jpg",            "email": "[email protected]",            "id": 999,            "name": "Mike Approver",            "role": "agent"          },          "created_at": "2025-02-25T15:00:00Z",          "id": "msg_123",          "message": "Can you provide more details about the expected ROI?"        }      ],      "created_at": "2025-02-25T14:15:00Z",      "created_by_user": {        "id": 888,        "name": "Sarah Requester",        "photo": {          "content_url": "https://example.zendesk.com/photos/888.jpg"        }      },      "decided_at": "2025-02-25T16:30:00Z",      "decisions": [        {          "decided_at": "2025-02-25T16:30:00Z",          "decided_by_user": {            "id": 999,            "name": "Mike Approver",            "photo": {              "content_url": "https://example.zendesk.com/photos/999.jpg"            }          },          "decision_notes": "Approved for Q1 budget",          "origination_type": "UI_ORIGINATION",          "status": "approved"        }      ],      "id": "01HX123DEF",      "message": "Please approve the hardware request",      "origination_type": "UI_ORIGINATION",      "status": "approved",      "subject": "Hardware Request",      "ticket_id": 102,      "withdrawn_reason": null    }  ],  "links": {    "next": null,    "prev": null  },  "meta": {    "after_cursor": null,    "before_cursor": null,    "has_more": false  }}
400 Bad Request
// Status 400 Bad Request
{  "errors": [    {      "code": "InvalidFilterParameter",      "title": "Invalid status. Allowed values: active, approved, rejected, withdrawn"    }  ]}

Create Approval Request

  • POST /api/v2/approval_requests

Creates one or more approval requests for a ticket.

When manual approval requests are turned off for the account, approval requests can still be created through this API. Approval requests created by the API have a Sent by value of API.

Allowed For

  • System users (flowstate)
  • Agents

Single approval request

To create a single approval request, supply a top-level assignee_user_id or assignee_group_id. This is helpful when only one approval is required or approvals need to be received in a specific order.

The response returns the created request under the approval_request key. See the Example body and Example response(s) sections below for the single-request request and response shapes.

Parallel approval requests

To create multiple approval requests at once, for the approvers to review and respond to in parallel, supply an approval_requests array. The approval request's subject and message are set once at the top level and apply to every individual approval request in the array.

The approval requests are created atomically as an array under the approval_requests key, and all share the same approval_workflow_instance_id. If any of the approval request entries are invalid, none of the requests are created. To avoid invalid entries, do the following:

  • Specify exactly one assignee_user_id or assignee_group_id for each entry in the approval_requests array.
  • Make sure you don't combine a top-level assignee_user_id or assignee_group_id with the

approval_requests array. Doing so returns a 422.

Example request:

curl https://{subdomain}.zendesk.com/api/v2/approval_requests \  -H "Content-Type: application/json" -X POST \  -d '{"ticket_id": 123, "subject": "Budget Approval", "message": "Please approve the Q1 budget", "approval_requests": [{"assignee_user_id": 101}, {"assignee_group_id": 202}]}' \  -v -u {email_address}/token:{api_token}

Example response:

{  "approval_requests": [    {      "id": "01KFP3S9EVXF9CKAYY080NV98C",      "approval_workflow_instance_id": "01KFP3S9EVXF9CKAYY080NV98D",      "subject": "Budget Approval",      "message": "Please approve the Q1 budget",      "status": "active",      "created_at": "2026-01-23T19:02:36Z",      "created_by_id": 789,      "assignee_user_id": 101,      "assignee_group_id": null,      "ticket_id": 123,      "origination_type": "API_ORIGINATION"    },    {      "id": "01KFP3S9EVXF9CKAYY080NV98E",      "approval_workflow_instance_id": "01KFP3S9EVXF9CKAYY080NV98D",      "subject": "Budget Approval",      "message": "Please approve the Q1 budget",      "status": "active",      "created_at": "2026-01-23T19:02:36Z",      "created_by_id": 789,      "assignee_user_id": null,      "assignee_group_id": 202,      "ticket_id": 123,      "origination_type": "API_ORIGINATION"    }  ]}

Example body

{  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123}

Code Samples

Curl
curl --request POST https://example.zendesk.com/api/v2/approval_requests \--header "Authorization: Bearer ${authToken}" \--header "Content-Type: application/json" \--data-raw '{  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123}'
Go
import (	"fmt"	"io"	"net/http"	"strings")
func main() {	url := "https://example.zendesk.com/api/v2/approval_requests"	method := "POST"	payload := strings.NewReader(`{  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123}`)	req, err := http.NewRequest(method, url, payload)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_requests")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""{  \"approval_attachment_tokens\": [    \"01JAR7ZK3M9Q2VX8B5C4D6E7F8\",    \"01JAR7ZK3M9Q2VX8B5C4D6E7F9\"  ],  \"assignee_user_id\": 456,  \"message\": \"Please approve this request for a new laptop for the engineering team\",  \"subject\": \"Laptop Purchase Approval\",  \"ticket_id\": 123}""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("POST", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');var data = JSON.stringify({  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123});
var config = {  method: 'POST',  url: 'https://example.zendesk.com/api/v2/approval_requests',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  data : data,};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requestsimport json
url = "https://example.zendesk.com/api/v2/approval_requests"
payload = json.loads("""{  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123}""")headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"POST",	url,	headers=headers,	json=payload)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_requests")request = Net::HTTP::Post.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")request.body = %q({  "approval_attachment_tokens": [    "01JAR7ZK3M9Q2VX8B5C4D6E7F8",    "01JAR7ZK3M9Q2VX8B5C4D6E7F9"  ],  "assignee_user_id": 456,  "message": "Please approve this request for a new laptop for the engineering team",  "subject": "Laptop Purchase Approval",  "ticket_id": 123})response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end
curl (single, assign to user)
curl https://{subdomain}.zendesk.com/api/v2/approval_requests \  -H "Content-Type: application/json" -X POST \  -d '{"message": "approval description", "subject": "approval subject", "assignee_user_id": 456, "ticket_id": 123}' \  -v -u {email_address}/token:{api_token}
curl (single, assign to group)
curl https://{subdomain}.zendesk.com/api/v2/approval_requests \  -H "Content-Type: application/json" -X POST \  -d '{"message": "approval description", "subject": "approval subject", "assignee_group_id": 789, "ticket_id": 123}' \  -v -u {email_address}/token:{api_token}
curl (parallel)
curl https://{subdomain}.zendesk.com/api/v2/approval_requests \  -H "Content-Type: application/json" -X POST \  -d '{"ticket_id": 123, "subject": "Budget Approval", "message": "Please approve the Q1 budget", "approval_requests": [{"assignee_user_id": 101}, {"assignee_group_id": 202}]}' \  -v -u {email_address}/token:{api_token}

Example response(s)

201 Created
// Status 201 Created
{  "approval_request": {    "assignee_group_id": null,    "assignee_user_id": 456,    "created_at": "2026-01-23T19:02:36Z",    "created_by_id": 789,    "id": "01KFP3S9EVXF9CKAYY080NV98C",    "message": "Please approve this request for a new laptop for the engineering team",    "origination_type": "API_ORIGINATION",    "status": "active",    "subject": "Laptop Purchase Approval",    "ticket_id": 123  }}
422 Unprocessable Entity
// Status 422 Unprocessable Entity
{  "errors": [    {      "code": "ApprovalRequestCreationFailed",      "title": "Approval request couldn't be sent because one active, approved, or denied request already exists"    }  ]}

Show Approval Clarification Flow Messages

  • GET /api/v2/approval_clarification_flow_messages/{approval_request_id}

Returns the clarification flow thread (comments exchanged between the requester and the approver) for an approval request.

Allowed For

  • Agents
  • End users who can view the approval request's ticket, or who are its assignee

Parameters

NameTypeInRequiredDescription
approval_request_idstringPathtrueThe id of the approval request

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://example.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV',  headers: {	'Authorization': 'Bearer ${authToken}',	'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://example.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_clarification_flow_messages/01ARZ3NDEKTSV4RRFFQ69G5FAV")request = Net::HTTP::Get.new(uri, "Authorization": "Bearer ${authToken}", "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
{  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "clarification_flow_messages": [    {      "author": {        "avatar": "https://company.zendesk.com/system/photos/12345/avatar.png",        "id": 12345,        "name": "Jane Doe",        "role": "end_user"      },      "created_at": "2026-09-29T14:32:00Z",      "id": "msg_123",      "message": "Can you clarify the budget line?",      "via": "SUPPORT"    }  ]}
403 Forbidden
// Status 403 Forbidden
{  "errors": "Access denied"}
404 Not Found
// Status 404 Not Found
{  "error": {    "message": "You’ve reached this page because what you were looking for does not exist or there’s been an error.",    "title": "Not Found"  }}

Withdraw Approval Workflow Instance

  • PATCH /api/v2/approval_workflow_instances/{workflow_instance_id}/withdraw

Withdraws every non-withdrawn approval request in the given workflow instance and marks the workflow instance as withdrawn. Works for both parallel and non-parallel workflow instances.

Allowed For

  • Agents who can manage approval requests and edit the associated ticket, and who are either the approval request's requester or the ticket's assignee

Parameters

NameTypeInRequiredDescription
workflow_instance_idstringPathtrueThe id of the approval workflow instance

Example body

{  "withdrawn_reason": "No longer needed"}

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw \  -H "Content-Type: application/json" -X PATCH \  -d '{"withdrawn_reason": "No longer needed"}' \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http"	"strings")
func main() {	url := "https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw"	method := "PATCH"	payload := strings.NewReader(`{  "withdrawn_reason": "No longer needed"}`)	req, err := http.NewRequest(method, url, payload)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""{  \"withdrawn_reason\": \"No longer needed\"}""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("PATCH", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');var data = JSON.stringify({  "withdrawn_reason": "No longer needed"});
var config = {  method: 'PATCH',  url: 'https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  data : data,};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requestsimport json
url = "https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw"
payload = json.loads("""{  "withdrawn_reason": "No longer needed"}""")headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"PATCH",	url,	headers=headers,	json=payload)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/withdraw")request = Net::HTTP::Patch.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")request.body = %q({  "withdrawn_reason": "No longer needed"})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
{  "approval_requests": [    {      "approval_workflow_instance_id": "01KFP3S9EVXF9CKAYY080NV98D",      "assignee_group": null,      "assignee_user": {        "id": 456,        "name": "Jane Approver"      },      "created_at": "2026-01-23T19:02:36Z",      "created_by_user": {        "id": 789,        "name": "John Requester",        "photo": {          "content_url": "https://company.zendesk.com/system/photos/789/photo.png"        }      },      "decided_at": null,      "decisions": [],      "id": "01KFP3S9EVXF9CKAYY080NV98C",      "message": "Please approve",      "origination_type": "API_ORIGINATION",      "status": "withdrawn",      "subject": "Budget Approval",      "ticket_id": 123,      "withdrawn_reason": "No longer needed"    }  ]}
400 Bad Request
// Status 400 Bad Request
{  "error": {    "message": "You passed an invalid value for the withdrawn_reason attribute.",    "title": "Invalid attribute"  }}
403 Forbidden
// Status 403 Forbidden
{  "errors": [    "Access denied"  ]}
404 Not Found
// Status 404 Not Found
{  "errors": [    "You’ve reached this page because what you were looking for does not exist or there’s been an error."  ]}
422 Unprocessable Entity
// Status 422 Unprocessable Entity
{  "errors": [    "Only a requester can withdraw the request."  ]}

Decide Approval Request

  • PATCH /api/v2/approval_workflow_instances/{workflow_instance_id}/approval_requests/{id}/decision

Records a decision (approve, reject, or withdraw) on an approval request, with optional notes.

Allowed For

  • The user or a member of the group assigned to review the approval request

The ticket requester, the ticket assignee, and the user who created the approval request are not allowed to decide on it, even when they are also the assignee.

Parameters

NameTypeInRequiredDescription
idstringPathtrueThe id of the approval request to decide on
workflow_instance_idstringPathtrueThe id of the approval workflow instance

Example body

{  "notes": "Looks good, approved",  "status": "approved"}

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision \  -H "Content-Type: application/json" -X PATCH \  -d '{"status": "approved", "notes": "Looks good, approved"}' \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http"	"strings")
func main() {	url := "https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision"	method := "PATCH"	payload := strings.NewReader(`{  "notes": "Looks good, approved",  "status": "approved"}`)	req, err := http.NewRequest(method, url, payload)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""{  \"notes\": \"Looks good, approved\",  \"status\": \"approved\"}""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("PATCH", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');var data = JSON.stringify({  "notes": "Looks good, approved",  "status": "approved"});
var config = {  method: 'PATCH',  url: 'https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  data : data,};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requestsimport json
url = "https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision"
payload = json.loads("""{  "notes": "Looks good, approved",  "status": "approved"}""")headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"PATCH",	url,	headers=headers,	json=payload)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C/decision")request = Net::HTTP::Patch.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")request.body = %q({  "notes": "Looks good, approved",  "status": "approved"})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
{  "approval_request": {    "approval_workflow_instance_id": "01KFP3S9EVXF9CKAYY080NV98D",    "assignee_group": null,    "assignee_user": {      "id": 456,      "name": "Jane Approver",      "photo": {        "content_url": "https://company.zendesk.com/system/photos/456/photo.png"      }    },    "created_at": "2026-01-23T19:02:36Z",    "created_by_user": {      "id": 789,      "name": "John Requester",      "photo": {        "content_url": "https://company.zendesk.com/system/photos/789/photo.png"      }    },    "decided_at": "2026-01-23T19:10:00Z",    "decisions": [      {        "decided_at": "2026-01-23T19:10:00Z",        "decided_by_user": {          "id": 456,          "name": "Jane Approver",          "photo": {            "content_url": "https://company.zendesk.com/system/photos/456/photo.png"          }        },        "decision_notes": "Looks good, approved",        "status": "approved"      }    ],    "id": "01KFP3S9EVXF9CKAYY080NV98C",    "message": "Please approve this request for a new laptop",    "origination_type": "API_ORIGINATION",    "status": "approved",    "subject": "Laptop Purchase Approval",    "ticket_details": {      "custom_fields": [],      "id": 123,      "priority": "normal",      "requester": {        "id": 789,        "name": "John Requester"      },      "status": "open"    },    "withdrawn_reason": null  }}
400 Bad Request
// Status 400 Bad Request
{  "error": {    "message": "You passed an invalid value for the status attribute.",    "title": "Invalid attribute"  }}
403 Forbidden
// Status 403 Forbidden
{  "errors": "Access denied"}
404 Not Found
// Status 404 Not Found
{  "error": {    "message": "You've reached this page because what you were looking for does not exist or there's been an error.",    "title": "Not Found"  }}
422 Unprocessable Entity
// Status 422 Unprocessable Entity
{  "errors": [    "This approval request has already been withdrawn and cannot be updated."  ]}

Create Approval Clarification Flow Message

  • POST /api/v2/approval_clarification_flow_messages

Adds a message to the clarification flow thread for an approval request and returns the full, updated thread.

Allowed For

  • The approval request's assignee or creator, the ticket assignee, or a member of the assigned group
  • Any user who can view the ticket

Example body

{  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "message": "Can you clarify the budget line?"}

Code Samples

curl
curl https://{subdomain}.zendesk.com/api/v2/approval_clarification_flow_messages \  -H "Content-Type: application/json" -X POST \  -d '{"approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV", "message": "Can you clarify the budget line?"}' \  -H "Authorization: Bearer {access_token}"
Go
import (	"fmt"	"io"	"net/http"	"strings")
func main() {	url := "https://example.zendesk.com/api/v2/approval_clarification_flow_messages"	method := "POST"	payload := strings.NewReader(`{  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "message": "Can you clarify the budget line?"}`)	req, err := http.NewRequest(method, url, payload)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_clarification_flow_messages")		.newBuilder();RequestBody body = RequestBody.create(MediaType.parse("application/json"),		"""{  \"approval_request_id\": \"01ARZ3NDEKTSV4RRFFQ69G5FAV\",  \"message\": \"Can you clarify the budget line?\"}""");
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("POST", body)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');var data = JSON.stringify({  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "message": "Can you clarify the budget line?"});
var config = {  method: 'POST',  url: 'https://example.zendesk.com/api/v2/approval_clarification_flow_messages',  headers: {	'Authorization': 'Bearer ${authToken}',	'Content-Type': 'application/json',  },  data : data,};
axios(config).then(function (response) {  console.log(JSON.stringify(response.data));}).catch(function (error) {  console.log(error);});
Python
import requestsimport json
url = "https://example.zendesk.com/api/v2/approval_clarification_flow_messages"
payload = json.loads("""{  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "message": "Can you clarify the budget line?"}""")headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"POST",	url,	headers=headers,	json=payload)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_clarification_flow_messages")request = Net::HTTP::Post.new(uri, "Authorization": "Bearer ${authToken}", "Content-Type": "application/json")request.body = %q({  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "message": "Can you clarify the budget line?"})response = Net::HTTP.start uri.hostname, uri.port, use_ssl: true do |http|	http.request(request)end

Example response(s)

201 Created
// Status 201 Created
{  "approval_request_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",  "clarification_flow_messages": [    {      "author": {        "avatar": "https://company.zendesk.com/system/photos/12345/avatar.png",        "id": 12345,        "name": "Jane Doe",        "role": "end_user"      },      "created_at": "2026-09-29T14:32:00Z",      "id": "msg_123",      "message": "Can you clarify the budget line?",      "via": "SUPPORT"    }  ]}
400 Bad Request
// Status 400 Bad Request
{  "error": {    "message": "You passed an invalid value for the via attribute.",    "title": "Invalid attribute"  }}
403 Forbidden
// Status 403 Forbidden
{  "errors": "Access denied"}
404 Not Found
// Status 404 Not Found
{  "error": {    "message": "You've reached this page because what you were looking for does not exist or there's been an error.",    "title": "Not Found"  }}
422 Unprocessable Entity
// Status 422 Unprocessable Entity
{  "errors": [    "This approval request has already been withdrawn and cannot be updated."  ]}

Show Approval Request

  • GET /api/v2/approval_workflow_instances/{workflow_instance_id}/approval_requests/{id}

Shows a single approval request nested under its approval workflow instance.

Allowed For

  • Agents assigned to the approval request

Parameters

NameTypeInRequiredDescription
idstringPathtrueThe ULID of the approval request to retrieve
workflow_instance_idstringPathtrueThe ULID of the approval workflow instance

Code Samples

curl
curl -H "Authorization: Bearer {access_token}" \  https://{subdomain}.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C
Go
import (	"fmt"	"io"	"net/http")
func main() {	url := "https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C"	method := "GET"	req, err := http.NewRequest(method, url, nil)
	if err != nil {		fmt.Println(err)		return	}	req.Header.Add("Authorization", "Bearer ${authToken}")	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://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C")		.newBuilder();
Request request = new Request.Builder()		.url(urlBuilder.build())		.method("GET", null)		.addHeader("Authorization", "Bearer ${authToken}")		.addHeader("Content-Type", "application/json")		.build();Response response = client.newCall(request).execute();
Nodejs
var axios = require('axios');
var config = {  method: 'GET',  url: 'https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C',  headers: {	'Authorization': 'Bearer ${authToken}',	'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://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C"headers = {	"Authorization": "Bearer ${authToken}",	"Content-Type": "application/json",}
response = requests.request(	"GET",	url,	headers=headers)
print(response.text)
Ruby
require "net/http"uri = URI("https://example.zendesk.com/api/v2/approval_workflow_instances/01KFP3S9EVXF9CKAYY080NV98D/approval_requests/01KFP3S9EVXF9CKAYY080NV98C")request = Net::HTTP::Get.new(uri, "Authorization": "Bearer ${authToken}", "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
{  "approval_request": {    "approval_workflow_instance_id": "01KFP3S9EVXF9CKAYY080NV98D",    "assignee_group": null,    "assignee_user": {      "id": 456,      "name": "Jane Approver",      "photo": {        "content_url": "https://company.zendesk.com/system/photos/456/photo.png"      }    },    "created_at": "2026-01-23T19:02:36Z",    "created_by_user": {      "id": 789,      "name": "John Requester",      "photo": {        "content_url": "https://company.zendesk.com/system/photos/789/photo.png"      }    },    "decided_at": null,    "decisions": [],    "id": "01KFP3S9EVXF9CKAYY080NV98C",    "message": "Please approve this request for a new laptop",    "origination_type": "API_ORIGINATION",    "status": "active",    "subject": "Laptop Purchase Approval",    "ticket_details": {      "custom_fields": [],      "id": 123,      "priority": "normal",      "requester": {        "id": 789,        "name": "John Requester"      },      "status": "open"    },    "withdrawn_reason": null  }}
403 Forbidden
// Status 403 Forbidden
{  "errors": "Access denied"}
404 Not Found
// Status 404 Not Found
{  "error": {    "message": "You’ve reached this page because what you were looking for does not exist or there’s been an error.",    "title": "Not Found"  }}