Authentication

API keys, where to put them, and what they gate

Every Ziptax request is authenticated with an API key tied to your account. This page covers where to get a key, the two ways to send it on a request, and the entitlements that control what different keys can do.

Get an API key

  1. Sign in to platform.zip.tax.
  2. Open API Keys in the dashboard.
  3. Generate a new key and copy the value. Keys are opaque strings; keep them out of client-side code and source control.

The same key works against every Ziptax API version (/request/v10 through /request/v60) and against the account metrics, TIC search, and cart calculation endpoints.

Two ways to send the key

Ziptax accepts the key either as a request header or as a query parameter. Both work on every versioned /request/v* endpoint.

$curl -H "X-API-Key: YOUR_API_KEY" \
> "https://api.zip-tax.com/request/v60?address=200+Spectrum+Center+Dr+Irvine+CA"

Headers keep the key out of URLs, which means out of server access logs, browser history, and referer headers. This is the recommended pattern for any production integration.

Option 2: key query parameter

$curl "https://api.zip-tax.com/request/v60?key=YOUR_API_KEY&address=200+Spectrum+Center+Dr+Irvine+CA"

The query-parameter form is useful for quick manual tests or for environments that can’t set custom headers. Avoid it in production: URLs get logged in more places than headers do.

Precedence when both are set

If a request carries both the X-API-Key header and a key= query parameter, Ziptax uses the header value and ignores the query parameter. Practically: if you start sending a header and forget to strip the query parameter, nothing breaks; the new header wins.

Which endpoints need a key

EndpointAuth required
GET /request/v10GET /request/v60Yes
GET /account/metrics and /account/v{N}/metricsYes
POST /search/ticYes
POST /calculate/cartYes (header only)
GET /data/ticNo, public
GET /system/healthNo, public
GET /system/metadataNo, public

The cart endpoint (/calculate/cart) is the one exception to the “header or query” rule: it accepts only the X-API-Key header.

What your key can do: entitlements

Each key carries a set of entitlements that gate specific features and quotas. When a call requires an entitlement your key doesn’t have, Ziptax returns a specific response code so you can detect it and respond gracefully.

EntitlementControlsError code if missing
request_rateRequests per minute, default 10,000108
geo_enabledAddress and lat/lng lookups (postal-code lookups don’t require it)Returned per endpoint
rate_loc_cancountryCode=CAN for Canadian rates112
product_ratestaxabilityCode for product-specific rules113
core_request_limitPer-period quota on base rate lookups107
geo_request_limitPer-period quota on geocoded lookups107

Entitlements are set when your key is provisioned and reflect your current plan. Upgrading or changing plans updates the entitlements on your existing key; you don’t need to rotate the key itself.

You can read your current usage against the core_request_limit and geo_request_limit quotas from the Account Metrics endpoint.

Invalid or missing keys

If the key you send is malformed, not in our database, or has been deactivated, Ziptax returns response code 101 with HTTP 401.

1{
2 "metadata": {
3 "version": "v60",
4 "response": {
5 "code": 101,
6 "name": "RESPONSE_CODE_INVALID_KEY",
7 "message": "Key format is not valid or key not found."
8 }
9 }
10}

Most 101s trace to one of:

  • Trailing whitespace or wrapping quotes from copy-paste.
  • Using a deactivated key (regenerate from the dashboard).
  • Sending the key to the wrong environment.
  • Using the key parameter but spelling it apiKey or api_key instead. Only lowercase key is accepted.

See Response Codes for the full list and how to branch on codes programmatically.

Rate limiting

Every authenticated /request/v* call is rate-limited per key over a 60-second sliding window. The limit is your request_rate entitlement; the default is 10,000 requests per minute.

Every response includes two headers so you can watch your headroom:

X-RateLimit-Limit: 10000
X-RateLimit-Remaining: 9847

When you exceed the limit you get HTTP 429 with response code 108. See Rate Limiting & Errors for backoff and retry guidance.

Key hygiene

A leaked key can generate billable traffic against your account until it’s rotated. Keep keys safe:

  • Store keys as environment variables or in a secrets manager. Don’t hardcode them in source files, config files checked into git, or front-end bundles. If a key is in a public repo, a scraper will find it within hours.
  • Use different keys per environment. Generate one key for production and a separate one for staging, CI, and local development. That way you can rotate or revoke one without affecting the rest.
  • Rotate after a suspected leak. Generate a new key from the dashboard, deploy it to your services, then deactivate the old key. The window between the two is usually seconds.
  • Never send the key to a client. Ziptax is a server-to-server API. Any call from a browser or mobile app should route through your backend, which holds the key.
  • Don’t log the raw key. If you need to log which key made a request for debugging, mask it. Ziptax’s internal logs show only the first 8 and last 4 characters of each key; mirror that pattern on your side.

Using keys with the SDKs

Each SDK accepts the key as a constructor argument and sets the header for you on every request:

1import os
2from ziptax import Ziptax
3
4client = Ziptax(api_key=os.environ["ZIPTAX_API_KEY"])
5rate = client.by_address(address="200 Spectrum Center Dr, Irvine CA")