USPS Batch Address Validation API: Validate 50 Addresses in One Call
Validating one address at a time works for a signup form. It doesn’t work when you’re cleaning a mailing list with 10,000 rows, importing a Shopify CSV, or running nightly data quality checks on your customer database.
RevAddress’s batch endpoint validates up to 50 addresses per call, processes them in parallel, and caches results for 24 hours so repeat lookups are free.
The endpoint
curl -X POST "https://api.revaddress.com/api/batch/validate" \
-H "X-API-Key: rv_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"addresses": [
{
"streetAddress": "1600 Pennsylvania Ave NW",
"city": "Washington",
"state": "DC",
"ZIPCode": "20500"
},
{
"streetAddress": "350 Fifth Avenue",
"city": "New York",
"state": "NY",
"ZIPCode": "10118"
},
{
"streetAddress": "1 Infinite Loop",
"city": "Cupertino",
"state": "CA"
}
]
}' Each address needs at minimum a streetAddress. City, state, and ZIP are optional but improve match accuracy. The API validates all addresses in parallel — a single slow address never blocks the rest.
Response format
{
"total": 3,
"successful": 3,
"failed": 0,
"results": [
{
"index": 0,
"status": "success",
"address": {
"streetAddress": "1600 PENNSYLVANIA AVE NW",
"city": "WASHINGTON",
"state": "DC",
"ZIPCode": "20500-0003"
},
"additionalInfo": {
"DPVConfirmation": "Y",
"carrierRoute": "C000",
"deliveryPoint": "00",
"vacant": "N"
},
"cached": false
},
{
"index": 1,
"status": "success",
"address": {
"streetAddress": "350 5TH AVE",
"city": "NEW YORK",
"state": "NY",
"ZIPCode": "10118-0110"
},
"additionalInfo": {
"DPVConfirmation": "Y",
"carrierRoute": "B999",
"deliveryPoint": "50",
"vacant": "N"
},
"cached": false
},
{
"index": 2,
"status": "success",
"address": {
"streetAddress": "1 INFINITE LOOP",
"city": "CUPERTINO",
"state": "CA",
"ZIPCode": "95014-2083"
},
"additionalInfo": {
"DPVConfirmation": "Y",
"carrierRoute": "C067",
"deliveryPoint": "01",
"vacant": "N"
},
"cached": false
}
],
"usage": {
"cached_hits": 0,
"fresh_lookups": 3
}
} The usage object tells you exactly how many addresses hit the cache vs required a fresh USPS lookup. Cached addresses don’t count against your monthly quota.
SDK examples
import requests
API_KEY = "rv_live_your_key_here"
BASE = "https://api.revaddress.com"
addresses = [
{"streetAddress": "1600 Pennsylvania Ave NW", "city": "Washington", "state": "DC"},
{"streetAddress": "350 Fifth Avenue", "city": "New York", "state": "NY"},
{"streetAddress": "742 Evergreen Terrace", "city": "Springfield", "state": "IL"},
# ... up to 50 per call
]
resp = requests.post(
f"{BASE}/api/batch/validate",
headers={"X-API-Key": API_KEY},
json={"addresses": addresses},
)
data = resp.json()
print(f"Validated {data['successful']}/{data['total']} addresses")
print(f"Cache hits: {data['usage']['cached_hits']}")
for result in data["results"]:
if result["status"] == "success":
addr = result["address"]
dpv = result["additionalInfo"]["DPVConfirmation"]
print(f" [{dpv}] {addr['streetAddress']}, {addr['city']}, {addr['state']} {addr['ZIPCode']}")
else:
print(f" [ERR] index {result['index']}: {result['error']}") Processing large lists
50 addresses per call is the max. For larger lists, chunk and send sequentially:
import requests
import time
def validate_batch(addresses, api_key):
resp = requests.post(
"https://api.revaddress.com/api/batch/validate",
headers={"X-API-Key": api_key},
json={"addresses": addresses},
)
return resp.json()
# Load your address list
all_addresses = load_from_csv("customers.csv") # Your loader
# Chunk into batches of 50
BATCH_SIZE = 50
results = []
for i in range(0, len(all_addresses), BATCH_SIZE):
chunk = all_addresses[i:i + BATCH_SIZE]
batch = validate_batch(chunk, "rv_live_your_key_here")
results.extend(batch["results"])
print(f"Processed {min(i + BATCH_SIZE, len(all_addresses))}/{len(all_addresses)}")
# Summary
deliverable = [r for r in results if r["status"] == "success"
and r["additionalInfo"]["DPVConfirmation"] == "Y"]
print(f"Deliverable: {len(deliverable)}/{len(results)}") The second time you run the same list, cached addresses return instantly and don’t count against your quota. This makes nightly validation runs practically free after the first pass.
Handling failures gracefully
Individual address failures never kill the batch. If one address can’t be validated (bad format, USPS timeout), the response marks that entry as "status": "error" while all other addresses succeed:
{
"total": 3,
"successful": 2,
"failed": 1,
"results": [
{ "index": 0, "status": "success", "address": { "..." : "..." }, "cached": false },
{ "index": 1, "status": "error", "error": "Validation failed", "address": null, "cached": false },
{ "index": 2, "status": "success", "address": { "..." : "..." }, "cached": true }
],
"usage": { "cached_hits": 1, "fresh_lookups": 2 }
} This uses Promise.allSettled under the hood — the same resilience pattern used in production payment systems.
Pricing comparison
Batch validation is where RevAddress’s pricing advantage becomes dramatic:
| Provider | Per validation | 10K addresses | 100K addresses |
|---|---|---|---|
| RevAddress (Growth $79/mo) | $0.003 | $30 | $300 |
| EasyPost | $0.01 | $100 | $1,000 |
| Shippo | $0.05/label (includes validation) | $500 | $5,000 |
| Smarty | $0.01 | $100 | $1,000 |
| Lob | $0.015 | $150 | $1,500 |
At 100K addresses, RevAddress is 3x cheaper than EasyPost and 17x cheaper than Shippo.
Growth tier ($79/month) includes 25,000 requests. Each cached address is free, so repeat validation of the same list costs nothing after the first run.
Requirements
- Tier: Growth ($79/mo) or above. Free and Starter tiers use single address validation instead.
- Max batch size: 50 addresses per request
- Caching: 24-hour TTL. Cached lookups don’t count against monthly quota.
- Rate limits: Standard tier limits apply (Growth = 300 req/min)
Next steps
- Get your API key — free tier to start, upgrade to Growth when you need batch
- Full API reference — all 41 endpoints
- Interactive API docs — try requests live in the browser
- Address validation quickstart — single-address validation tutorial
- Pricing — compare all tiers
Ready to migrate?
293 tests. 41 routes. USPS-approved. Flat monthly pricing.