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.

  1. In the app's manifest.json file, add a setting object to the top-level parameters property. Set the object's secure property to true.

    {  ...  "parameters": [    {      "name": "apiToken",      "type": "text",      "secure": true    }  ]}

    For other supported properties, see Setting properties.

  2. 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    },  ]}
  3. In the app's request() call, use a {{setting.NAME}} placeholder for the secure setting's value. Set the secure 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.

  4. 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.

  1. 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:

  2. 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"  }}
  3. In manifest.json, add a setting object to the top-level parameters property. Set the object's type to oauth.

    {  "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"  }}
  4. In the app's request() call, use a {{setting.NAME}} placeholder for the token. Set the secure 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);});
  5. 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:

  1. Include a jwt object in the request() 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's exp 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 the iat and exp claims. If you specify the iat or exp 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.

  2. 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.