Making API requests from a Zendesk app
You can use the Zendesk Apps framework (ZAF) client's request() method to make REST API calls and other HTTP requests from a client-side Zendesk app. The method lets you:
- Avoid cross-domain restrictions when calling third-party APIs
- Avoid leaking secrets in the browser when making authenticated requests
- Manage OAuth 2.0 access tokens for third-party services
- Authenticate Zendesk API requests using browser cookies
The method returns the result of a request as a JavaScript Promise object. The method doesn't support uploading or downloading binary files.
Making a request to a third-party API
By default, the request()
method routes requests to non-Zendesk URLs through a
Zendesk proxy server. For example, the following request makes an API call using
a proxy server.
const client = ZAFClient.init();
const options = {
url: "https://api.example.com",
type: "GET",
};
client.request(options).then((response) => {
console.log(response);
});
To explicitly use a Zendesk proxy server, set the cors
option to false. The
following request is equivalent to the previous one.
const client = ZAFClient.init();
const options = {
url: "https://api.example.com",
type: "GET",
cors: false,
};
client.request(options).then((response) => {
console.log(response);
});
Benefits of using a Zendesk proxy server
Using a Zendesk proxy server helps you avoid same-origin policy restrictions. The restrictions can prevent client-side requests from accessing resources on another domain. Server-side requests made using a proxy don't have the same restrictions.
Using a Zendesk proxy server also gives you access to the following ZAF features:
These features aren't available outside of the request()
method.
Note: Zendesk proxy servers do not support the use of underscores in headers for API requests. For example, client-id
is supported but client_id
is not.
Using secure settings
The settings for client-side HTTP requests are visible in a browser's dev tools. These settings often include secrets, such as API authentication credentials. Leaking secrets in the browser creates a security risk.
Secure settings let you safely use secrets in an HTTP request. Instead of the
actual value, you use a setting placeholder in request()
calls. Only the
placeholder, not the value, is displayed in the browser's dev tools. The Zendesk
proxy server later inserts the setting's value outside the browser.
Secure setting requirements
To use secure settings in a request, the responding server must:
-
Allow requests from Zendesk IP addresses. You can get these IP address ranges using the List Zendesk Public IPs endpoint
-
Provide a valid and complete SSL certificate chain. For example,
curl https://{your-server}/
won't fail with SSL errors using a standard set of root certificates.
Configuring and passing a secure setting
A secure setting requires changes to the app's manifest file. A Zendesk admin must also configure the setting during app installation.
-
In the app's manifest.json file, add a setting object to the top-level
parameters
property. Set the object'ssecure
property to true.{
...
"parameters": [
{
"name": "apiToken",
"type": "text",
"secure": true
}
]
}
For other supported properties, see Setting properties.
-
In manifest.json, add the domain for the API endpoint to the top-level domainWhitelist array. Don't include "https://" in the value.
{
...
"domainWhitelist": [ "api.example.com" ],
"parameters": [
{
"name": "apiToken",
"type": "text",
"secure": true
},
]
}
-
In the app's
request()
call, use a{{setting.NAME}}
placeholder for the secure setting's value. Set thesecure
option to true.const options = {
url: "https://api.example.com/list",
type: "GET",
headers: {
Authorization: "Basic {{setting.apiToken}}",
},
accepts: "application/json",
secure: true,
};
client.request(options).then((response) => {
console.log(response);
});
Note: You can't use a secure setting placeholder outside of a
request()
call. -
When installing the app, the admin receives a prompt to enter the secure setting's value.
When the app makes the request()
call, the browser's dev tools only display
the setting placeholder. The Zendesk proxy server inserts the setting's value
outside of the browser.
For security reasons, the value of a secure setting is hidden after an admin submits the form.
Secure setting limitations
-
The value of a secure setting can't exceed 1,024 characters.
-
You can't use secure settings outside the
request()
method. CORS requests and Zendesk API requests don't support secure settings. -
You can't convert a secure setting to a regular installation setting. You can only delete a secure setting by removing it from the app's manifest.
-
You can't convert a regular installation setting to a secure setting. Create a new secure setting instead.
-
The ZCLI web server doesn't support secure settings. As a workaround, you can use ZCLI to package, upload, and update the app. See Packaging and installing a private Zendesk app and Updating a private Zendesk app.
Managing third-party OAuth access tokens
ZAF uses an oauth
setting
type to manage third-party
OAuth access tokens. If an app includes this setting type, an OAuth prompt is
displayed during app installation.
A Zendesk admin can use this prompt to start an OAuth flow with the third-party service. If the flow completes, ZAF stores the resulting access token.
You can pass a setting placeholder for the token to request()
calls. Only the
placeholder, not the token, is displayed in the browser's dev tools. The Zendesk
proxy server later inserts the token outside the browser.
Important: The oauth
setting type only supports the authorization code
grant type. You can't use the setting with other OAuth grant types.
Using a third-party OAuth access token
The oauth
setting requires changes to the app's manifest file. A Zendesk admin
must also complete an OAuth flow during app installation.
-
Create an OAuth client in the third-party service. These steps vary based on the service. Set the client's callback URL as "https://
zis.zendesk.com/api/services/zis/connections/oauth/callback". When done, the service should provide a client id and secret. The service's documentation should also provide:
-
An authorization URL for authorization code requests
-
A token URL for access token requests. If the OAuth flow succeeds, this URL returns an access token response.
-
-
In the app's manifest.json file, add a top-level oauth object. Set the object's property values using the OAuth client details from step 1.
{
...
"oauth": {
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET",
"authorize_uri": "https://api.example.com/oauth/authorize",
"access_token_uri": "https://api.example.com/oauth/access_token",
"scope": "read write"
}
}
-
In manifest.json, add a setting object to the top-level
parameters
property. Set the object'stype
tooauth
.{
"parameters": [
{
"name": "token",
"type": "oauth"
}
],
"oauth": {
"client_id": "CLIENT_ID",
"client_secret": "CLIENT_SECRET",
"authorize_uri": "https://api.example.com/oauth/authorize",
"access_token_uri": "https://api.example.com/oauth/access_token",
"scope": "read write"
}
}
-
In the app's
request()
call, use a{{setting.NAME}}
placeholder for the token. Set thesecure
option to true.const options = {
url: "https://api.example.com/list",
type: "GET",
headers: {
Authorization: "Bearer {{setting.token}}",
},
secure: true,
};
client.request(options).then((response) => {
console.log(response);
});
-
When an admin installs the app, an OAuth Authentication section is displayed. The section contains a link with the text Sign in with {app_name}.
The admin can click the link to start an OAuth flow with the third-party service. If the admin completes the OAuth flow, the OAuth Authentication section displays a check mark icon.
When the app makes the request()
call, the browser's dev tools only display
the setting placeholder. The Zendesk proxy server inserts the access token
outside of the browser.
Refreshing third-party access tokens
ZAF automatically refreshes expired access tokens if the access token
response
includes non-empty expires_in
and refresh_token
values. ZAF can't refresh
access tokens for a third-party service that doesn't provide these values.
Using OAuth parameters
Some third-party services include custom query parameters in the OAuth
authorization code
response.
For example, the following authorization code response includes a custom shop
parameter.
https://example.com/redirect?code=xyz&state=abc&shop=myshop
To store such a parameter's value, add a setting object to the parameters
property in manifest.json. For the object's name
, use the query
parameter's key with an oauth_
prefix. Set the object's type
to "hidden".
{
...
"parameters": [
{
"name": "token",
"type": "oauth"
},
{
"name": "oauth_shop",
"type": "hidden"
}
]
...
}
You can access the setting value using the ZAF client's metadata() method.
client.metadata().then((metadata) => {
console.log(metadata.settings.oauth_shop);
});
Encoding and sending ZAF JWTs
The request()
method supports encoding and sending JSON web tokens
(JWTs). You can use a ZAF JWT to
send arbitrary data in a request. You can also use the JWT to ensure requests
from a Zendesk app are legitimate. The responding server can verify the JWT's
signature using a shared secret key. The Zendesk proxy server inserts the
encoded JWTs outside the browser.
Important: ZAF JWTs are signed but not encrypted. Don't include secrets, such as passwords, in ZAF JWTs.
To encode and send a ZAF JWT token:
-
Include a
jwt
object in therequest()
call's options. In the object, include the following properties:-
A
jwt.algorithm
of "HS256". ZAF JWT signatures only support the HS256 algorithm. -
A
jwt.secret_key
that uses a secure setting for its value. -
An optional
jwt.expiry
duration in seconds. ZAF uses this duration to calculate the JWT'sexp
claim. The expiration period starts at the JWT's issuance. The duration defaults to five minutes. -
An optional
jwt.claims
object that contains claims for the JWT, including any custom claims. The Zendesk proxy server automatically adds theiat
andexp
claims. If you specify theiat
orexp
claims, the server overwrites them.
Also, set the
secure
option to true.const options = {
url: "https://api.example.com/post",
type: "POST",
headers: {
Authorization: "Bearer {{jwt.token}}",
},
jwt: {
algorithm: "HS256",
secret_key: "{{setting.shared_secret}}",
expiry: 3600,
claims: {
jti: "8883362531196.326",
iss: "some_subdomain",
},
},
secure: true,
};
client.request(options).then((response) => {
console.log(response);
});
Important: ZAF JWTs only support the Latin-1 (ISO 8859-1) subset of UTF-8 characters. Non-UTF-8 characters are parsed as UTF-8.
-
-
In the
request()
call, use a{{jwt.token}}
placeholder for the ZAF JWT.const options = {
url: "https://api.example.com/post",
type: "POST",
headers: {
Authorization: "Bearer {{jwt.token}}",
},
jwt: {
algorithm: "HS256",
secret_key: "{{setting.shared_secret}}",
expiry: 3600,
claims: {
jti: "8883362531196.326",
iss: "some_subdomain",
},
},
secure: true,
};
client.request(options).then((response) => {
console.log(response);
});
When the app makes the request()
call, the browser's dev tools only display
the placeholder in the request. The Zendesk proxy server inserts the JWT outside
of the browser.
Making a CORS request
If an API supports Cross-Origin Resource Sharing
(CORS), you can make
client-side requests to the API without a Zendesk proxy server. This is called a
CORS request. To make a CORS request, set the cors
option to true.
const options = {
url: "https://api.example.com/list",
type: "GET",
cors: true,
};
client.request(options).then((response) => {
console.log(response);
});
Important: Only use a CORS request for API calls that don't require authentication. Using secrets in a CORS request can leak the secrets in the browser.
CORS requests aren't routed through a Zendesk proxy server and don't support the following ZAF features:
If cors
is true, the secure
option is ignored.
Making a Zendesk API request
You can also use the request()
method to make requests to a Zendesk API. To
authenticate the requests, the ZAF client uses the browser's Zendesk session
cookie.
In the request, use the endpoint's path in the url
option. Don't include the
Zendesk domain or subdomain.
For example, the following request calls the Ticketing API's Create Ticket endpoint.
const options = {
url: "/api/v2/tickets.json",
type: "POST",
contentType: 'application/json',
data: JSON.stringify({
ticket: {
subject: "Test ticket #1",
comment: {
body: "This is a test ticket"
}
}
}),
};
client.request(options).then((response) => {
console.log(response);
});
The following request calls the Core Sales CRM API's Create a Deal endpoint.
const options = {
url: "/v2/deals",
type: "POST",
contentType: "application/json",
data: JSON.stringify({
data: {
name: "Website Redesign",
contact_id: 1
}
}),
};
client.request(options).then((response) => {
console.log(response);
});
Requests to Zendesk APIs are always made from the browser, regardless of the
cors
option. You can't make a request to a Zendesk API using a Zendesk proxy
server.
Rate limits for Zendesk API requests
request()
calls to Zendesk APIs are subject to rate limits. See Rate
limits in the ZAF API reference.
If a request()
call is rate-limited, ZAF auto-retries the request after a
delay. To disable the retry behavior, set the autoRetry
option to false
.
const options = {
url: "/api/v2/tickets.json",
type: "GET",
autoRetry: false,
};
client.request(options).then((response) => {
console.log(response);
});
Limitations for Zendesk API requests
-
You can't make
request()
calls to the following Zendesk APIs: -
You can't make
request()
calls to the Core Sales CRM API from a Support app. -
You can't make
request()
calls to the following Zendesk APIs from a Sell app: -
You can't use the
request()
method to call another Zendesk instance. Attempts to call another instance may result in a "403 is not a proxyable URI" error. To make an API request to another Zendesk instance, use a server-side Zendesk app instead.