The Zendesk User API, Lookups Done Right
Every integration needs the same thing first: turn an email address into a user ID. Here's how to do it reliably with the Zendesk user API, and why search isn't the answer.
Why this is the Zendesk user API call you make most
Almost nothing in Zendesk is addressed by email. Tickets carry a requester_id. Organisation memberships carry a user_id. Comments carry an author_id. All of them are numbers.
Your system, meanwhile, knows people by email address or by its own customer ID. So the first thing any integration does, before it can create a ticket or read a history or attach a note, is resolve a human into a Zendesk user ID.
Get this right and everything downstream is easy. Get it wrong and you'll create a duplicate user, attach a ticket to the wrong person, or fail intermittently in a way that only shows up under load.
Lookup by email address
The user search endpoint takes a query, and an email address is a perfectly good query.
curl -u "you@acme.com/token:$ZD_TOKEN" \
"https://acme.zendesk.com/api/v2/users/search.json?query=ada@example.com"You get back a users array. Usually with one entry. Sometimes with none, and occasionally with more than one, because the query matches rather than looks up exactly.
Handle all three cases. A single result you take. Zero results means create the user, or fail loudly if creating isn't appropriate. More than one is the interesting case, and the honest answer is that you shouldn't silently pick the first. Log it, pick deterministically, and get a human to look, because two users sharing an address pattern is a data problem that will keep costing you.
One more subtlety: an address might be a secondary identity rather than a primary email. That's a real user and a real match, and it is exactly the case that a naive comparison of user.email against your address will get wrong.
Lookup by external id, which is better
If you set external_id when you created the user, you have a stable key that does not change when somebody gets married or moves company.
GET /api/v2/users/search.json?external_id=crm-88213There's also a batch form for fetching many users at once by ID or by external ID in a single request, which is the cheapest way to hydrate a list you already have. If you're about to loop over forty user IDs with forty requests, use that instead.
The argument for external id over email is simple. Emails change and people have several. Your own identifier is one per human and it never moves. The cost is that you have to have set it, which is why every guide including this one keeps repeating it.
Why not just use the search API
The general Zendesk search API can find users too, with type:user and a query. For a lookup it is the wrong tool, for three reasons.
Index lag. General search runs against an index that trails the database by seconds. Create a user and immediately search for them and you may get nothing. If your flow is create-then-find, you have built a race condition.
A tighter rate limit. Search has its own allowance, lower than the general one. Spending it on lookups you make thousands of times a day is a poor trade.
Fuzzier matching. Search is designed to find things a human is hunting for. A lookup wants an exact answer, and a partial match returned confidently is worse than nothing.
The user endpoints are the right tool. Use general search when a person is searching, not when a program is resolving.
Cache it, and handle the misses
Resolution results barely change. The mapping from an email address to a user ID is stable for months at a time, which makes it an obvious cache.
Keep a local table of your identifier, their email and their Zendesk user ID, written whenever you resolve or create. Consult it first, call the API on a miss, write back the result. That single table removes most of the API traffic from a typical integration and gives you something to reconcile against when things look wrong.
Invalidate on the things that actually change: a user merged into another, an email address updated, a user deleted. If you need to know about those promptly, the incremental export endpoint for users gives you everything changed since a timestamp, which is a far better sync than re-resolving everyone nightly.
And decide, once, what happens on a miss. Create silently? Create and flag? Refuse? Every integration needs an answer and the ones that don't have one end up creating a new user every time somebody's address is capitalised differently.
Frequently asked questions
How do I find a user by email or external ID?
Use the dedicated lookups. The Zendesk find user by email API endpoint takes an exact address, and a Zendesk external id lookup takes your own identifier, which is more reliable. Zendesk show_many users fetches a batch in one call.
How do I find a user by email with the Zendesk user API?
Query the user search endpoint with the address, then handle zero, one and multiple results explicitly. The address may also be a secondary identity rather than the primary email.
Can I look a user up by my own ID?
Yes, if you set external_id when creating them. It is the more stable key, because email addresses change and people have several.
Why not use the general search API for user lookups?
Index lag, a tighter rate limit and fuzzier matching. General search is for humans hunting, the user endpoints are for programs resolving.
What should I do when a lookup returns two users?
Do not silently take the first. Log it, choose deterministically, and get somebody to look, because it usually means two records for one person.
How do I fetch many users at once?
Use the batch endpoint that accepts a list of IDs or external IDs in one request, rather than looping over individual lookups.
Same person, different address, second ticket
Ticket Merger merges duplicate Zendesk tickets using requester, subject keywords and ticket fields inside a time window, so the pair never reaches two agents.
Start free trial14-day free trial. No credit card required.