Skip to main content
The Forest Zendesk app lets you view and act on your data without leaving Zendesk. Access customer records, trigger actions and see related data inline in ticket sidebars.

How it works

The app reaches your back-end through the Forest Gateway, whose API service exposes a flat REST contract to browser UIs. Each Zendesk agent signs in with their own Forest account, and every call travels to your back-end as that person. Their roles, permissions and scopes apply exactly as they do in Forest.
Versions up to and including 1.1.1 went through the Forest MCP Server, and they speak a protocol the Gateway API does not serve. Changing the URL on one of those installations is not enough: update the app first, then repoint it at your Gateway URL. 1.3.0 renamed the setting to forestGatewayApiUrl, so the update leaves the field empty and an admin has to enter the URL again before anyone can sign in.

Prerequisites

Before installing the app, your tech team needs a Gateway API that a browser can reach:
  1. A Gateway serving your Forest back-end, either embedded in your Node.js agent (addGateway({ api })) or deployed as the standalone Gateway.
  2. OAuth enabled on it, which is what lets each Zendesk agent sign in with their Forest account.
  3. The app’s iframe origin allowed, because the app calls the Gateway from the browser. Recent Gateways allow it on their own.
From @forestadmin/agent 1.111.0 and the standalone Gateway 1.1.0, the Gateway API always allows https://*.apps.zdusercontent.com, the domain Zendesk serves every app’s iframe from, so there is nothing to configure. The Forest app’s own origin is https://1231469.apps.zdusercontent.com, its Marketplace id, the same on every installation. Your allowedOrigins entries are added to that one, never in place of it.
On an older Gateway, allow-list https://*.apps.zdusercontent.com yourself. Your Zendesk URL does not work in its place: a Zendesk app runs in an iframe served from Zendesk’s own app domain, so the Origin the browser sends is that iframe’s, never https://your-subdomain.zendesk.com, and every call is refused with 403 origin_not_allowed.
The embedded option needs @forestadmin/agent 1.109.0 or later, which ships the Gateway and its addGateway() method, and loads @forestadmin/agent-bff at runtime, an optional peer dependency of @forestadmin/agent, at exactly the version the agent declares. Install or upgrade both in one command: npm install @forestadmin/agent@latest @forestadmin/agent-bff@latest. On an older agent the call throws agent.addGateway is not a function.
If you restrict OAuth clients with the Gateway’s allowedOAuthClients, keep forestadmin.com in the list: the app’s sign-in redirect runs through app.forestadmin.com, and without that entry the Zendesk app itself is rejected with invalid_client.
A build served locally with zcli apps:server runs from http://localhost:4567. Allow-list that origin too while you develop.
Embedding needs the Node.js agent. With a Ruby back-end, run the standalone Gateway. Already running addBff() or forest-bff? Move to the Gateway first, through Moving from addBff() or From forest-bff, then point the app at the new …/api URL. Make a note of the URL your Gateway answers on. You’ll need it when installing the Zendesk app:
Without tokenEncryptionKey (or FOREST_GATEWAY_API_TOKEN_ENCRYPTION_KEY standalone), the Gateway boots but its OAuth routes stay disabled, and nobody can sign in from Zendesk. GET {your-gateway-url}/health reports configured.oauth so you can check before installing.

Installing the Zendesk app

1

Install from the Marketplace

Find the Forest app in the Zendesk Marketplace and click Install.
2

Open your Zendesk Admin Center

Enter your Zendesk URL and click Next. You are redirected to the Admin Center.
You need to be an Admin in Zendesk to access the Admin Center.
3

Fill in the installation form

  • Forest Gateway API URL (forestGatewayApiUrl): your Gateway URL, from the table above
  • Optionally, restrict which Zendesk roles and groups get access to the Forest app
A form labelled Forest MCP URL, suggesting a URL ending in /mcp, means the installation has not updated past 1.1.1 yet. Update it first, then enter your Gateway URL. Nothing else to configure: versions up to 1.0.2 also carried a contextField parameter, and it is gone. The app matches tickets from their own content.
Updating from 1.2.0 or earlier leaves the URL field empty, since 1.3.0 renamed the setting to forestGatewayApiUrl and Zendesk does not carry the old value over. Enter your Gateway URL again after the update, or no Zendesk agent can sign in.
4

Install

Click Install.
The Forest Zendesk app is now installed. Add it to your ticket sidebar from the Apps tab.
The Forest app in a Zendesk ticket sidebar, showing the Connect with Forest Admin button

Signing in

Each Zendesk agent connects with their own Forest account, once:
  1. In the Forest app, click Connect with Forest Admin
  2. Sign in to Forest in the popup that opens, as you usually would to reach your project
  3. The popup closes and the app shows your data
There is nothing to pick. The project and environment come from the Gateway your tech team deployed, and your team is resolved from your Forest account, so two Zendesk agents on the same ticket can see different records.

Your Forest app is now configured in Zendesk!

It matches the ticket sender against your Forest data, surfaces the relevant Customer, User or Partner record, and suggests the actions that resolve the ticket.
The Data tab listing the user matched from the ticket sender, with its related records

How a ticket is matched to a record

You configure nothing here. On every ticket the app reads the signals the ticket already carries, then searches your collections for them, with no model in the loop. It reads the requester’s Zendesk id and email, plus the emails, URLs and record ids it finds in the subject and description. It recognizes five record id formats:
  • a UUID
  • a prefixed id, 2 to 8 letters and an underscore followed by at least 10 letters and digits mixing both, as in abc_9f8e7d6c5b4a
  • a 24-character hexadecimal ObjectId
  • a #1234 reference of 4 digits or more
  • a number of 6 digits or more
Because a prefixed id must carry both letters and digits, snake_case words, file names and version strings are not read as ids. It searches the fields your schema exposes, picked by name: Each record id goes to every collection whose key can hold it, a UUID to a Uuid or String field, a number to a Number or String field, a prefixed id or ObjectId to a String field. In each collection the app searches one id field, id when it fits and otherwise the first id field that does, plus the collection’s external user id fields. A Zendesk user id field only receives numbers. No collection is skipped for its position in your schema, so a ticket carrying an order id and a customer id can surface both records. Exact hits outrank partial ones, join-like collections lose 30 points, and the best-scoring records surface in the Data tab. Each ticket is capped at 6 searches at once, 30 collections for the Zendesk id, 15 for emails, and 100 searches in total, so a wide schema does not fan out indefinitely. Searches past that budget are dropped, and the app logs how many in the browser console.
A collection that stores the Zendesk user id under a name outside that convention, crm_user_ref or support_id for instance, is never searched for it. Expose a field whose name follows the convention, or rely on the email signal.

Where AI is used

Two features call a model, both in the Actions tab, both through the Gateway API’s relay, POST {basePath}/api/agent/v1/ai/query, which relays to Forest’s AI proxy with the signed-in Zendesk agent’s session. The Gateway holds the Forest token, and the browser never sees it. Suggested action names come back through a filter: the app keeps the ones that match a real action and drops the rest, so a hallucinated name never reaches a button. Every ticket field is sanitized before it leaves, with injection markers stripped and lengths capped. Records and relations browsed in the Data tab never reach the AI proxy, and neither does matching.
The AI relay is served whenever sign-in is configured on the Gateway, which GET {your-gateway-url}/health reports as configured.ai. Stay out of the Actions tab and nothing is sent: the Data tab, the search bar and the matching never call it.

Troubleshooting

  • Check GET {your-gateway-url}/health, configured.oauth must be true
  • Confirm forestGatewayApiUrl points at the Gateway API (…/api), not at the agent root and not at an MCP URL
  • On a CORS error in the browser console, check the Gateway version first: before @forestadmin/agent 1.111.0 and the standalone Gateway 1.1.0, the allow-list must hold https://*.apps.zdusercontent.com or the exact https://1231469.apps.zdusercontent.com. Your Zendesk tenant URL never covers the iframe origin. The rejected preflight answers 204 with no headers, so the 403 origin_not_allowed never reaches the browser, and the Gateway logs BFF preflight origin rejected with the origin it refused
  • Confirm their Forest role grants read access to the collection. The app shows what that person is allowed to see, nothing more
  • Check that one of your collections carries the requester’s email, or an id field the naming convention recognizes. Nothing is configured per installation, so a schema that stores the Zendesk id under an off-convention name stays invisible to the matcher
  • Use the search bar to confirm the record exists and is readable: if search finds it but the ticket does not, the gap is in the signals, not in permissions
Actions the caller’s permissions do not confirm are hidden. Check the role’s action permissions in Project Settings → Roles.