Rate Limiting & Errors
Rate Limiting & Errors
Ziptax enforces a per-API-key rate limit on every call to the
/request/v* endpoints. If you send too many requests in a short
window, you’ll get an HTTP 429 Too Many Requests with application
code 108. This page covers the exact window, the response headers,
the recommended backoff strategy, and the shape of every error response
so you can branch on it reliably.
The rate limit
Every API key has a request_rate entitlement that sets how many
requests it can make per 60-second sliding window. The default on new
keys is 10,000 requests per minute. Higher limits are available on
Pro and Enterprise plans. Reach out to
support@zip.tax if you’re hitting the
ceiling.
The window is a rolling 60 seconds, not a fixed minute boundary. If you send 10,000 requests at 12:00:30, you won’t get another success until 12:01:30, not at the top of the next minute.
The rate limit applies per API key across all API versions (v10 to v60) and across regions. Splitting traffic across v50 and v60 from the same key won’t get you extra headroom.
The TIC feed is separate
GET /data/tic has its own 100 requests per minute limiter that
isn’t shared with /request/v*. It’s meant as a reference feed, so
pull the catalog once, cache it, and refresh weekly. See
Taxability Information Codes for the recommended pattern.
Rate limit headers
Every response (success or 429) includes two headers describing the current state of your window:
Read these on every response, not just errors. They’re your early warning signal that you’re approaching the limit.
Ziptax does not send a Retry-After header on 429s. Use the
backoff strategy below instead of waiting for the server to tell you
when to retry.
What a 108 looks like
When you exceed the limit, Ziptax returns HTTP 429 with the standard
response envelope and code: 108:
There are no baseRates or taxSummaries fields on a 108, so branch
on the code before reading rate data.
Backoff strategy
The right pattern depends on whether your traffic is user-driven or batch.
User-driven traffic (checkout, quote)
A single retry with a short delay is usually enough, because you’re probably hitting the limit from burst traffic that will clear on its own:
Batch traffic (catalog sync, nightly reconciliation)
For large jobs, smooth the traffic proactively instead of reacting to
429s. Watch X-RateLimit-Remaining and slow down before you hit zero:
A simpler approach is client-side pacing: if your entitlement is 10,000 per minute, cap your sender at ~150 requests per second and you’ll never trip 108s.
The error envelope
All Ziptax errors share the same envelope as success responses. The
numeric code at metadata.response.code is the stable contract.
Always branch on it, not on the HTTP status or the human-readable
message.
Legacy versions (v50 and earlier) return the same fields at the top
level as rCode, rName, and rMessage instead of nested under
metadata.response. The numeric codes are identical.
Errors you’ll actually hit
Most production integrations only ever see a handful of codes. Here’s what to wire up first:
See the full code list for every value Ziptax can return.
Common mistakes
Treating 429 as a generic 'server problem'
HTTP 429 is specifically a rate limit signal, so back off rather than retrying hard. A tight retry loop on 429 will make it worse because every retry counts against the window.
Parsing the message field
Parsing the message field
The message string is documented here for humans but may be
refined over time. Branch on the numeric code instead; it’s
stable across versions.
Waiting for Retry-After
Waiting for Retry-After
Ziptax doesn’t send Retry-After. Use exponential backoff or
pre-emptively pace your sender based on X-RateLimit-Remaining.
Hammering /data/tic in a loop
Hammering /data/tic in a loop
The TIC feed is a reference table, not a per-request lookup. Pull it once, cache it, and refresh weekly. Its 100 req/min limiter will cut you off fast if you treat it like the rate endpoint.
Retrying 4xx input errors
Codes 101 through 105, 109, and 111 are deterministic input failures. Retrying won’t help. Fix the input, or surface the error to the caller.
