Zendesk API Errors (401, 422, 429) and How to Fix Them
You fired off a request to the Zendesk REST API, and instead of clean JSON you got a number: `401`, `422`, or — the classic that shows up only in production, never in testing — `429`. The Zendesk API is well-behaved, but its errors are terse. The status code tells you which class of thing went wrong; the response body (which a lot of people never read) usually tells you exactly what.
This is a developer's field guide to the Zendesk API errors you'll actually hit, with the real cause and the exact fix for each, plus copy-paste request and response examples. If you want the conceptual background first — base URLs, auth, pagination — start with the Zendesk API explained; this post assumes you're already making calls and just want the error to stop. Everything here is verified against Zendesk's developer docs as of June 2026; rate-limit numbers in particular change, so confirm them in your own account.
First: read the error, don't guess
Before any specific fix, build the habit that resolves most Zendesk API errors in one pass — read the whole response, not just the status line. Two things carry the signal:
- The status code classifies the failure:
4xxmeans you sent something wrong (auth, permissions, validation, rate);5xxmeans Zendesk had a problem. - The response body names the specifics. Zendesk returns a JSON body for most
4xxerrors with anerrorkey and often adetailsmap pointing at the offending field. (One exception: some400 Bad Requestresponses come back astext/plainfor API-level errors, so don't assume JSON.)
Always log the status code, the response body, and the response headers. The headers carry Retry-After on a 429, and dumping the Authorization header (carefully, in a dev environment) is the single fastest way to debug a 401. Here's the minimum you want to capture:
curl -sS -D - \
-u "[email protected]/token:YOUR_API_TOKEN" \
"https://your_subdomain.zendesk.com/api/v2/tickets/123.json"
# -D - prints response headers (status line, Retry-After, X-Rate-Limit) to stdout
With that in hand, the codes below become quick to diagnose.
401 Unauthorized — Zendesk can't authenticate you
A 401 means Zendesk couldn't identify who's calling. It never even got to checking permissions — the credentials themselves didn't parse or weren't accepted. This is almost always an auth-header problem, and it's the most common Zendesk API error by a wide margin.
The correct auth header patterns
There are two auth methods you'll use, and mixing them up is the #1 cause of 401.
API token via Basic auth. The username is not just your email — it's your email with /token appended, then a colon, then the token, all Base64-encoded:
Authorization: Basic base64( {email_address}/token:{api_token} )
So with curl you let -u do the encoding, and the literal /token suffix is required:
# CORRECT — note the /token suffix on the username
curl -u "[email protected]/token:abc123APITOKEN" \
"https://your_subdomain.zendesk.com/api/v2/users/me.json"
If you build the header yourself, encode [email protected]/token:abc123APITOKEN — for example btoa(${email}/token:${token}) in JS — and send Authorization: Basic <that string>.
OAuth access token via Bearer. OAuth tokens do not go in a Basic header. They use the Bearer scheme:
# CORRECT — OAuth uses Bearer, never Basic
curl -H "Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN" \
"https://your_subdomain.zendesk.com/api/v2/users/me.json"
Common causes and fixes
- Omitting the
/tokensuffix.[email protected]:TOKENis treated as email/password, not email/token — and fails. Add/token. - Bad Base64 / hidden whitespace. A trailing newline or space sneaks into the encoded string (common when piping through shell tools). Re-encode and log the exact header.
- OAuth token sent as Basic (or an API token sent as Bearer). Match the scheme to the credential.
- Token revoked, expired, or deleted. Someone deleted the API token in Admin Center, or the OAuth token expired. Regenerate it.
- Password/token access disabled. Admins can switch off password access and/or token access for the API in Admin Center security settings. If basic email:password auth started 401-ing, that's the likely reason — switch to an API token or OAuth.
- Wrong subdomain or environment. Credentials are scoped to one account. A sandbox token will 401 against production (and vice versa). Confirm the subdomain in the URL matches the account that issued the credential.
Where these credentials live: API tokens and OAuth clients are both created in Admin Center → Apps and integrations → APIs → Zendesk API (the OAuth tab is in the same area). If you can't find a token to regenerate, that's the page.
The screenshot above is that admin area — API tokens and OAuth clients are managed under Apps and integrations → APIs. Generate a token there, test it with the users/me.json call above, and a clean 200 confirms your auth header is correct before you debug anything else.
403 Forbidden — authenticated, but not allowed
A 403 is the opposite of a 401 in an important way: Zendesk knows who you are, it just won't let that identity do this. Don't go re-checking your token format — the credential is fine. The problem is permissions or scope.
{
"error": "Forbidden",
"description": "You do not have access to this page. Please contact the account owner of this help desk for further help."
}
Common causes and fixes
- End-user credentials hitting an agent/admin endpoint. Many endpoints require an agent or admin. If you authenticated as an end user (or a token tied to one), agent-only routes return
403. Use credentials with the right role. - Agent calling an admin-only action. Some operations (account settings, certain user changes) require an admin. Bump the calling identity's role or use an admin token.
- OAuth token missing the required scope. Scopes are fixed at token creation — you can't widen them afterward. If a token was minted with
readonly and youPOST, you'll get403. Mint a new token with the scope you need (e.g.tickets:write). - Feature not on your plan. Some endpoints are gated to specific Suite plans or add-ons. If the feature isn't on your plan, even an admin gets
403. Confirm the endpoint is available on your plan tier. - IP allowlist restrictions. If the account restricts API access by IP, requests from an unlisted address are rejected. Add your server's IP to the allowlist.
- Cross-brand or suspended access. Reaching a resource that belongs to another brand, or calling as a suspended/downgraded agent, also returns
403.
The quick triage: if the same credential works on some endpoints but 403s on one, it's a scope/role/plan issue on that endpoint — not your auth.
422 Unprocessable Entity — your data didn't validate
A 422 means your request authenticated, parsed, and was understood — but the content failed Zendesk's validation rules. Your JSON is syntactically fine; a value inside it isn't acceptable. This is the friendliest error to debug because Zendesk tells you exactly which field is wrong — in the details object.
Say you try to create a user with an email that already exists:
curl -u "[email protected]/token:abc123APITOKEN" \
-X POST "https://your_subdomain.zendesk.com/api/v2/users.json" \
-H "Content-Type: application/json" \
-d '{"user": {"name": "Jane Doe", "email": "[email protected]"}}'
Zendesk responds 422 with a body like this:
{
"error": "RecordInvalid",
"description": "Record validation errors",
"details": {
"email": [
{
"description": "Email: [email protected] is already being used by another user",
"error": "DuplicateValue"
}
]
}
}
The fix lives in details: the key (email) is the offending field, and the array spells out why (DuplicateValue). (The exact human-readable description string can vary slightly by API version, so match on the structure and the error type rather than the prose.)
Common causes and fixes
- Missing a required field. Creating a ticket without
comment, or a user withoutname, fails.detailswill name the blank field (error: "blank"). Add it. - Invalid value. A value outside the allowed set — an unknown
priority, a malformed date, a non-existentgroup_id.detailsflags the field. Send a valid value. - Duplicate. As above — an email or external ID already in use (
DuplicateValue). Look the existing record up and update it instead of creating a new one, or use a different value. - Bad field format. A custom field expecting a number gets a string, or a tag has illegal characters. Match the field's expected type.
A related code worth knowing: 409 Conflict. Zendesk returns it when simultaneous requests touch the same resource. For writes you want to be idempotent, design retries so a replay doesn't double-create — key off your own external ID, check-then-create, and treat a duplicate (422) on retry as "already done" rather than a hard failure.
429 Too Many Requests — you hit the rate limit
A 429 means you exceeded Zendesk's rate limit. It's the error that never shows up in local testing and then floods your logs the moment you run a backfill or a busy sync. The fix is not "send slower and hope" — Zendesk tells you exactly how long to wait.
Honor the Retry-After header
Every 429 comes back with a Retry-After header giving the number of seconds to wait before retrying. Read it and wait — don't immediately hammer again.
HTTP/1.1 429 Too Many Requests
Retry-After: 38
X-Rate-Limit: 700
A minimal, correct retry loop honoring it:
import time, requests
def zendesk_get(url, auth, max_retries=5):
for attempt in range(max_retries):
resp = requests.get(url, auth=auth)
if resp.status_code != 429:
return resp
wait = int(resp.headers.get("Retry-After", 2 ** attempt)) # fall back to backoff
time.sleep(wait)
resp.raise_for_status()
If Retry-After is ever absent, fall back to exponential backoff (1s, 2s, 4s, 8s…) with a little jitter so parallel workers don't all retry in lockstep.
The rate limits themselves
Zendesk's per-minute account limit for the Support/Help Center API depends on your Suite plan. As of June 2026 the documented per-minute limits are:
| Suite plan | Requests / minute |
|---|---|
| Team | 200 |
| Growth | 400 |
| Professional | 400 |
| Enterprise | 700 |
| Enterprise Plus | 2,500 |
The High Volume API add-on raises a qualifying plan to 2,500 requests/minute (it sets the limit to 2,500 — it doesn't add 2,500 on top). On top of the account limit, specific endpoints have their own tighter limits: Incremental Exports is about 10 requests/minute (30 with High Volume), Update Ticket throttles to roughly 30 updates per 10 minutes per user per ticket, and some list endpoints throttle once you page deep. These numbers are plan-dependent and Zendesk changes them — treat the table as a starting point and confirm in the rate limits docs and your own account.
Stop hitting it in the first place
Backoff handles the spike; the real fix is making fewer, smarter calls — Zendesk's own best practices for this:
- Sideload related data.
?include=users,groupspulls associated records in one response instead of an N+1 storm of follow-up calls. - Use cursor-based pagination (
page[size],links.next) rather than offset paging, which is itself rate-limited past the first pages. - Pull bulk data with the Incremental Exports API, not by paging every ticket — it's built for large, periodic syncs.
- Use bulk endpoints like Update Many Tickets (up to 100 records per request) instead of one call per record.
- Cache data that doesn't change every minute (groups, custom field definitions, org records) instead of re-fetching it.
- Throttle proactively — spread requests evenly under your per-minute ceiling rather than bursting.
404 and 5xx — the quick ones
404 Not Found is almost always a URL or ID problem: a typo in the path, a missing .json, a resource that was deleted, or an ID that belongs to a different account/subdomain. Re-check the endpoint path and confirm the record exists with a list call before you fetch it by ID.
5xx (500, 502, 503) means the problem is on Zendesk's side, not yours. Don't refactor your code — check status.zendesk.com for an incident, then retry with backoff. A 503 may include a Retry-After header (e.g. during scheduled maintenance); honor it the same way you do for a 429.
Best practices that prevent most API errors
A short checklist that heads off the errors above before they happen:
- Store tokens securely. Keep API tokens and OAuth secrets in environment variables or a secrets manager — never in source control or client-side code. Rotate them if exposed.
- Always read the response body and headers. The
detailsmap (422) andRetry-After(429) tell you the fix directly. Log status, body, and headers on every failure. - Build retries in from day one. Honor
Retry-After, fall back to exponential backoff with jitter, and cap attempts. Make writes idempotent so a retry can't double-create. - Minimize calls. Sideload, cache, paginate with cursors, and use bulk endpoints — fewer requests means fewer
429s and a faster integration. - Check the status page before debugging a 5xx. Save yourself an hour of chasing a bug that's actually a Zendesk incident.
- Match scope to need. Mint OAuth tokens with exactly the scopes the integration uses — narrow enough to be safe, wide enough to avoid
403.
Where an AI agent fits in
If you're hitting these errors because you're hand-rolling an integration that reads tickets, drafts replies, tags, and routes, it's worth knowing there's a layer that handles the plumbing for you. Macha is an AI agent layer that runs on top of Zendesk — it's not a help desk and not a Zendesk replacement. Under the hood, Macha talks to Zendesk through the same REST API covered here via its connector, which means it manages the auth handshake, honors rate limits and Retry-After backoff, and deals with pagination and validation so you're not the one writing retry loops and chasing 429s.
Keeping it honest for a dev audience: it's still an integration with its own setup, and it's only as useful as the knowledge and tools you connect it to. On cost, Macha bills per AI action — each automated step an agent takes (drafting a reply, tagging, routing, resolving) — not per ticket or per resolution, because most of the work is the steps along the way, not a single tidy outcome. If your reason for touching the API is "automate repetitive ticket work," that's the line where a managed agent can save you the integration maintenance. You can try it free — 7-day free trial, no credit card required. If you're building the integration yourself, the Zendesk API guide, webhooks, and how the ticketing system models its objects are the references to keep open.
Frequently asked questions
Why am I getting a 401 from the Zendesk API when my token is correct? The most common cause is the username format. For API-token Basic auth the username must be email/token (with the literal /token suffix), not just your email — so the full string you Base64-encode is [email protected]/token:YOUR_TOKEN. Other culprits: sending an OAuth token with Basic instead of Bearer, hidden whitespace in the encoded header, a revoked token, password/token access disabled in Admin Center, or using a sandbox token against production.
What's the difference between a 401 and a 403 on the Zendesk API? A 401 means Zendesk can't authenticate you — it can't tell who's calling (bad or missing credentials). A 403 means it authenticated you fine but you're not authorized for that action — wrong role (end user on an agent endpoint), an OAuth token missing the needed scope, an IP restriction, or a feature not on your plan. If one credential works on some endpoints but 403s on another, it's a permissions issue, not an auth-format one.
How do I find which field caused a Zendesk 422 error? Read the response body. A 422 returns error: "RecordInvalid" with a details object keyed by field name — e.g. details.email with an array describing the problem ("blank", "DuplicateValue", an invalid value). The key is the offending field and the array tells you why. Fix that field and resend.
How do I handle Zendesk API 429 rate limit errors? Read the Retry-After response header — it gives the seconds to wait — then wait that long and retry. If it's missing, fall back to exponential backoff with jitter. Longer term, reduce calls: sideload related records (?include=), use cursor pagination, pull bulk data with Incremental Exports, batch writes with Update Many, and cache slow-changing data.
What are Zendesk's API rate limits? They're per-minute, per-account, and vary by Suite plan — roughly Team 200, Growth/Professional 400, Enterprise 700, Enterprise Plus 2,500 requests per minute, with the High Volume API add-on raising a qualifying plan to 2,500. Specific endpoints (Incremental Exports, Update Ticket, deep list pages) have their own tighter limits. These change over time, so confirm against Zendesk's rate-limits doc and your own account.
A Zendesk API call returns 500 or 503 — is it my code? Probably not. 5xx codes are server-side. Check status.zendesk.com for an active incident or maintenance window, then retry with backoff. A 503 may carry a Retry-After header you should honor.
The bottom line
Zendesk API errors are diagnosable once you read the whole response, not just the status code. 401 is authentication — fix the auth header (email/token for Basic, Bearer for OAuth). 403 is permission — check role, scope, plan, and IP rules; the credential itself is fine. 422 is validation — the details object names the exact bad field. 429 is rate limiting — honor Retry-After, back off, and make fewer calls via sideloading, cursor pagination, bulk endpoints, and caching. 404 is a wrong URL or ID, and 5xx is Zendesk's side, so check the status page before you touch your code. Store credentials securely, build retries in from the start, and read the body every time — do that and most Zendesk API errors fix themselves in a single pass. For the wider picture, see the Zendesk API explained.
Error behavior and rate limits verified against Zendesk's developer documentation, June 2026. Zendesk revises rate limits and API behavior periodically — confirm specifics in the developer docs and your own account.
Add AI agents to your Zendesk
Macha resolves tickets end to end, right on top of Zendesk — no migration.
Zendesk
Freshdesk
Gorgias
Front
Shopify
Stripe
Slack
Notion
Google Workspace
Confluence

