For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
SupportLog InSign Up
GuidesAPI Reference
GuidesAPI Reference
    • Welcome to Ziptax
      • Quickstart
      • How to create an API key
      • How to find a TIC
      • Authentication
      • Collection Requirements and Nexus
      • Response Codes
      • Rate Limiting & Errors
      • Account Metrics
Logo
SupportLog InSign Up
On this page
  • The rate limit
  • The TIC feed is separate
  • Rate limit headers
  • What a 108 looks like
  • Backoff strategy
  • User-driven traffic (checkout, quote)
  • Batch traffic (catalog sync, nightly reconciliation)
  • The error envelope
  • Errors you’ll actually hit
  • Common mistakes
  • Related
Reference

Rate Limiting & Errors

How Ziptax throttles traffic, what headers to read, and how to back off cleanly
Was this page helpful?
Previous

Account Metrics & Usage

Check your plan quota, usage, and account status with /account/v{N}/metrics

Next
Built with

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:

HeaderMeaning
X-RateLimit-LimitYour request_rate entitlement, the ceiling for the window.
X-RateLimit-RemainingRequests still available before you’ll start getting 108s.

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:

1{
2 "metadata": {
3 "version": "v60",
4 "response": {
5 "code": 108,
6 "name": "RESPONSE_CODE_REQUEST_LIMIT_MET",
7 "message": "API request limit met.",
8 "definition": "http://api.zip-tax.com/request/v60/schema"
9 }
10 }
11}

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:

1import time, requests
2
3def lookup_with_retry(address, max_attempts=3):
4 for attempt in range(max_attempts):
5 res = requests.get(
6 "https://api.zip-tax.com/request/v60",
7 headers={"X-API-Key": "YOUR_API_KEY"},
8 params={"address": address},
9 )
10 data = res.json()
11 code = data["metadata"]["response"]["code"]
12
13 if code == 100:
14 return data
15 if code == 108 and attempt < max_attempts - 1:
16 # exponential backoff: 1s, 2s, 4s
17 time.sleep(2 ** attempt)
18 continue
19 return data # non-retryable or out of attempts

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:

1def batch_lookup(addresses):
2 results = []
3 for address in addresses:
4 res = requests.get(
5 "https://api.zip-tax.com/request/v60",
6 headers={"X-API-Key": "YOUR_API_KEY"},
7 params={"address": address},
8 )
9 results.append(res.json())
10
11 remaining = int(res.headers.get("X-RateLimit-Remaining", "10000"))
12 if remaining < 100:
13 # pre-emptively pause; we're close to the limit
14 time.sleep(5)
15 return results

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.

1{
2 "metadata": {
3 "version": "v60",
4 "response": {
5 "code": 109,
6 "name": "RESPONSE_CODE_ADDRESS_INCOMPLETE",
7 "message": "The provided address is missing, incomplete, or not a valid address.",
8 "definition": "http://api.zip-tax.com/request/v60/schema"
9 }
10 }
11}

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:

CodeWhenWhat to do
100Normal path.Read taxSummaries[0].rate.
108Rate limit.Back off (see above). Transient, so retry is safe.
109Address didn’t resolve.Surface to the user, don’t retry.
101Bad API key.Alert your team; probably a config issue.
106Unknown server error.Exponential backoff, then escalate.
112Canadian lookup without entitlement.Don’t retry; upgrade plan or skip.
113taxabilityCode without entitlement.Don’t retry; upgrade plan or skip.

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

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

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

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.

Related

Response Codes

The full table of codes 100 through 113.

Account Metrics

Query your current usage and quota with /account/v{N}/metrics.

REST API

The endpoints that enforce the rate limit.