CDXZipStream Technologies
REST API

Build with the CDXZipStream API

Every tool in the add-ins is a plain HTTPS/JSON endpoint you can call from any language. ZIP and postal lookup, distance and radius, Census demographics, geocoding, routing, and USPS address verification. One key header, no SDK required.

Base URL
https://api.cdxzipstream.com

Quickstart

  1. 1. Create an account and activate a plan. The Free plan works to start.
  2. 2. Open Account, then API Keys and copy your cdx_live_… key.
  3. 3. Send it as X-API-Key on every /v1 call. Keep it secret, it spends your credits.

curl

Your first call
curl -s "https://api.cdxzipstream.com/v1/zip/80401" \
  -H "X-API-Key: cdx_live_YOUR_KEY"

Python

requests
import requests

BASE = "https://api.cdxzipstream.com"
HEADERS = {"X-API-Key": "cdx_live_YOUR_KEY"}

# Single lookup
r = requests.get(f"{BASE}/v1/zip/80401", headers=HEADERS)
r.raise_for_status()
print(r.json())

# The X-Credits-* headers ride on the verify endpoints only.
# Anywhere else, read the balance from /v1/account, which is free to call.
print(requests.get(f"{BASE}/v1/account", headers=HEADERS).json())

# Distance between pairs
r = requests.post(
    f"{BASE}/v1/distance",
    headers=HEADERS,
    json={"pairs": [["80401", "10001"], ["90210", "60601"]], "unit": "miles"},
)
print(r.json())

JavaScript / TypeScript

fetch
const BASE = "https://api.cdxzipstream.com";
const headers = {
  "X-API-Key": "cdx_live_YOUR_KEY",
  "Content-Type": "application/json",
};

// Geocode a list of addresses
const res = await fetch(`${BASE}/v1/geocode`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    addresses: ["1600 Pennsylvania Ave NW, Washington, DC 20500"],
  }),
});

if (res.status === 402) throw new Error("Out of credits - top up your account");
if (!res.ok) throw new Error(`CDXZipStream ${res.status}`);

console.log(await res.json());
// Geocode returns no credit headers - read the balance from GET /v1/account

Mixed bulk work

POST /v1/batch runs different operations over large lists in one round trip, which is cheaper on latency than looping single calls.

POST /v1/batch request body
{
  "operations": [
    { "op": "zip",         "args": ["80401"] },
    { "op": "demographics", "args": ["10001"] },
    { "op": "distance",    "args": ["80401", "10001"] }
  ]
}

Endpoints at a glance

Full request and response schemas for each one are in the Swagger UI and ReDoc.

Lookup

GET/v1/zip/{zip_code}City, county, state, lat/long and population for a US ZIP or international postal code
POST/v1/zip/batchThe same lookup over a list of codes in one request
GET/v1/demographics/{zip_code}Census and ACS demographics: population, income, age, education, housing
POST/v1/tractResolve a US Census Tract FIPS / GEOID

Distance and proximity

GET, POST/v1/distanceGreat-circle distance between pairs of codes, in miles or kilometres
POST/v1/radiusEvery ZIP within a radius of a center point. Priced by rows returned, so limit is the cost control
POST/v1/closestThe N closest ZIPs to a point. Priced by rows returned, so n is the cost control
POST/v1/closest-in-listThe closest entry from a caller-supplied list, for store and depot assignment
POST/v1/findSearch ZIPs by city, county or state. Priced by rows returned, so limit is the cost control

Geocoding

POST/v1/geocodeAddresses to latitude and longitude
POST/v1/revgeocodeCoordinates back to an address
POST/v1/staticmap-urlA signed static map image URL, single or multi-marker

Routing

POST/v1/routeDriving distance and time between stops
POST/v1/optimizeMulti-stop route optimization for delivery and field work. The method parameter, straight, here or aco, sets both the quality and the credit weight per stop

Address verification

GET, POST/v1/verifyValidate and standardize a US address to USPS form with ZIP+4 and deliverability
POST/v1/verify/batchThe same verification over a mailing list

Bulk and account

POST/v1/batchMixed operations over large lists in a single request. Radius, closest and find are priced here exactly as on their own endpoints, and each returns its limit and a truncated flag per item
GET/v1/pricingThe live rate card: credit cost per operation, rows_per_credit and the row-priced ops, plus tiers and per-call caps. Free to call
GET/v1/accountYour plan, monthly grant remaining and top-up balance. Free to call
GET/v1/healthService health. Free to call

Credits and metering

Billing is credit-based and pooled per account. Every key on an account draws from the same monthly grant plus prepaid top-up balance, so adding keys never adds capacity.

Per-item operations such as ZIP and distance cost one credit per item, address verification two, geocoding four, and routing three per pair — the operations that make a paid provider call are priced above the ones served locally. Radius, closest and find are priced by the rows they return, one credit per 25 rows with a minimum of one, so the limit you ask for is the cost control. Optimization costs stops times a method weight. GET /v1/pricing returns the live rate card and costs nothing to call, so read costs from there rather than hardcoding them.

The address verification endpoints carry the headers below, and X-Credits-Remaining is omitted on unlimited plans. Elsewhere, read the balance from GET /v1/account.

Response headers
X-Credits-Charged: 2
X-Credits-Remaining: 8431

Error codes

Failures are plain HTTP status codes with a JSON body explaining the cause. Refused calls are never performed and never charged.

401Missing, invalid or revoked key, or a suspended account
402Out of credits. Both the monthly grant and the top-up balance are exhausted
403The operation needs a plan or add-on your account does not hold
413The request exceeds a per-call cap for your tier, such as batch size, optimize stops or radius reach in miles
429Burst rate limit, pooled per account. A completed call also charges the bucket for the provider calls it made

Per-item misses inside a batch are returned per item and do not fail the request.

Frequently asked questions

How do I authenticate?

Send your CDXZipStream API key in the X-API-Key header on every /v1 call. A ?key= query parameter is also accepted where a header is awkward, though the header is preferred. Keys look like cdx_live_… and are issued from your account.

Is there an OpenAPI spec I can generate a client from?

Yes. https://api.cdxzipstream.com/openapi.json is OpenAPI 3.1 and is the source of truth behind both the Swagger UI and ReDoc views. It imports directly into Postman, Insomnia, Bruno and Hoppscotch, and works with openapi-generator for typed clients in most languages.

How is the API billed?

In credits, pooled per account. An account holds one monthly grant plus an optional prepaid top-up balance, and every key on the account draws from that same pool, so issuing more keys never adds capacity. Per-item operations such as ZIP and distance cost one credit per item, address verification two, geocoding four, and routing three per pair — the operations that make a paid provider call are priced above the ones served locally. Radius, closest and find are priced by the rows they return, one credit per 25 rows with a minimum of one, so the limit you ask for is the cost control. Route optimization costs stops times a method weight. GET /v1/pricing returns the live rate card and is free to call.

How do I know how many credits a call used?

The address verification endpoints, POST /v1/verify and POST /v1/verify/batch, return X-Credits-Charged and X-Credits-Remaining headers, and X-Credits-Remaining is omitted on unlimited plans. Other endpoints do not send those headers, so read your balance from GET /v1/account, which is free to call.

What happens when I run out of credits?

The call is refused with HTTP 402 and is not performed or charged. Radius, closest and find are the exception: because they are priced by rows returned, a balance too small for the full allowance clamps the result to fewer rows instead of refusing it. Add a prepaid top-up or move to a larger plan and calls resume immediately.

Are there rate or size limits?

Yes. A burst rate limit applies per account and returns 429 when exceeded. The same bucket is also charged for the provider calls a completed request made, so a request that leans hard on geocoding or routing can leave the next one waiting even at a modest call rate; pause briefly rather than shrinking the request. Local-only work is not charged that way. Per-call caps vary by tier and return 413 when exceeded, covering batch size, optimize stops and how far a radius may reach in miles. The number of rows radius, closest and find return is clamped to your tier's maximum rather than rejected. Split oversized work across requests or use POST /v1/batch.

Do I need the Excel or Sheets add-in to use the API?

No. The API is a standalone HTTPS/JSON service. The add-ins, the Claude MCP connector and your own code all call the same endpoints with the same key and draw on the same credit pool.

Can I try calls without writing any code?

Yes. Open the Swagger UI, click Authorize, paste your key, then use Try it out on any endpoint. Each request body is pre-filled with a working example. Calls made this way are real and meter credits like any other.

Get a key and make your first call

Start free. The same key works in the API, the Excel and Sheets add-ins, and Claude.