USPS v3 REST API client — OAuth 2.0, address validation, tracking, labels, rates. Drop-in replacement for usps-api (retired Jan 2026).
Project description
usps-v3
USPS v3 REST API client — OAuth 2.0, address validation, tracking, labels, rates. Drop-in replacement for the usps-api PyPI package (retired January 2026).
Direct USPS integration. OAuth 2.0. No middleman. No per-label fees.
Migrating from
usps-api? That package (13,700+ downloads/month) uses the retired USPS Web Tools XML API (shut down January 25, 2026). This SDK uses the new v3 REST API with OAuth 2.0. See Migration from usps-api below.
Don't want to manage USPS credentials? RevAddress provides a managed USPS v3 API with flat monthly pricing, rate limit handling, and BYOK support. Get a free sandbox key — no credit card required.
Migrating from EasyPost or USPS Web Tools?
RevAddress provides a managed USPS v3 API with flat monthly pricing — no per-label fees. If you're migrating from EasyPost (shutting down March 17, 2026) or the legacy USPS Web Tools XML API:
- Migration Guide — Step-by-step from XML to REST
- EasyPost vs RevAddress — Feature and pricing comparison
- Endpoint Mapping — Every legacy endpoint mapped to v3
Save 81% vs EasyPost at 5,000 labels/mo ($79/mo flat vs $420 in per-label fees). Get started →
Install
pip install usps-v3
Quick Start
from usps_v3 import Client
# Credentials from USPS Business Customer Gateway
client = Client(client_id="your-id", client_secret="your-secret")
# Or set USPS_CLIENT_ID and USPS_CLIENT_SECRET environment variables:
# client = Client()
# Validate an address (FREE)
result = client.addresses.validate(
street_address="1600 Pennsylvania Ave NW",
city="Washington",
state="DC",
zip_code="20500",
)
print(result["address"]["ZIPPlus4"]) # "0005"
# Track a package (FREE)
info = client.tracking.track("9400111899223033005282")
print(info["statusCategory"]) # "Delivered"
# Get delivery time estimates (FREE)
standards = client.standards.estimates("10001", "90210")
# Find drop-off locations (FREE)
locations = client.locations.dropoff("20500", mail_class="PRIORITY_MAIL")
# Get rate quotes
rates = client.prices.domestic("10001", "90210", weight=2.5)
print(rates["rates"]["rateOptions"][0]["totalPrice"])
# International rates
intl = client.prices.international("10001", "CA", weight=3.0)
# Create shipping labels (requires USPS enrollment + COP claims)
label = client.labels.create(
from_address={"streetAddress": "123 Sender St", "city": "New York", "state": "NY", "ZIPCode": "10001"},
to_address={"streetAddress": "456 Recipient Ave", "city": "LA", "state": "CA", "ZIPCode": "90001"},
mail_class="PRIORITY_MAIL",
weight=2.0,
)
print(label["trackingNumber"])
# Void a label
client.labels.void("9400111899223033005282")
Features
| Feature | Endpoint | Auth Required |
|---|---|---|
| Address Validation | addresses.validate() |
OAuth only |
| City/State Lookup | addresses.city_state() |
OAuth only |
| Package Tracking | tracking.track() |
OAuth only |
| Service Standards | standards.estimates() |
OAuth only |
| Drop-off Locations | locations.dropoff() |
OAuth only |
| Domestic Prices | prices.domestic() |
OAuth only |
| International Prices | prices.international() |
OAuth only |
| Label Creation | labels.create() |
OAuth + Payment Auth |
| Label Void | labels.void() |
OAuth only |
Authentication
The SDK handles OAuth 2.0 token lifecycle automatically:
- Token caching: Tokens are cached in memory and on disk (
~/.usps-v3/tokens.json) - Auto-refresh: Tokens refresh automatically 30 minutes before expiry
- Thread-safe: Safe for concurrent use across threads
Getting Credentials
- Register at USPS Business Customer Gateway
- Create an application in the API developer portal
- Note your
client_idandclient_secret
For label creation, you also need:
- CRID (Customer Registration ID)
- MIDs (Mailer IDs — master + label owner)
- EPA (Enterprise Payment Account)
- COP claims linking at cop.usps.com
See our USPS CRID/MID enrollment guide for step-by-step instructions.
client = Client(
client_id="...",
client_secret="...",
crid="56982563",
master_mid="904128936",
label_mid="904128937",
epa_account="1000405525",
)
Error Handling
from usps_v3 import Client, AuthError, ValidationError, RateLimitError, APIError
try:
result = client.addresses.validate(street_address="123 Main St")
except ValidationError as e:
print(f"Bad input: {e} (field: {e.field})")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
except AuthError as e:
print(f"Auth failed: {e}")
except APIError as e:
print(f"USPS error ({e.status_code}): {e}")
USPS Rate Limits
The v3 API defaults to 60 requests/hour (down from unlimited in Web Tools). The SDK does not enforce this limit — USPS returns 429 when exceeded.
To request a higher limit, contact USPS at emailus.usps.com. See our USPS rate limits guide for details.
Migration from usps-api
The usps-api PyPI package (13,700+ downloads/month) uses the retired USPS Web Tools XML API (shut down January 25, 2026). If you're migrating from usps-api or any Web Tools XML integration:
| Web Tools (XML) | v3 SDK (Python) |
|---|---|
<AddressValidateRequest> |
client.addresses.validate(...) |
<CityStateLookupRequest> |
client.addresses.city_state(...) |
<TrackFieldRequest> |
client.tracking.track(...) |
<RateV4Request> |
client.prices.domestic(...) |
| User ID auth | OAuth 2.0 (automatic) |
| XML response parsing | Python dicts (automatic) |
| Unlimited requests | 60/hr default (request increase) |
See our complete migration guide and Web Tools endpoint mapping for detailed migration instructions.
RevAddress Managed API
If you'd rather not manage USPS OAuth credentials, rate limits, and enrollment yourself, RevAddress offers a managed REST API:
- Drop-in USPS v3 API — same endpoints, managed OAuth
- Flat monthly pricing — no per-label fees (from $29/mo)
- Rate limit handling — 120-600 req/min depending on plan
- BYOK support — bring your own USPS credentials
- 293 tests, 41 routes — production-grade infrastructure
Get a free sandbox key — address validation, tracking, and rate shopping included. No credit card required.
Development
git clone https://github.com/revereveal/usps-v3.git
cd usps-v3
pip install -e ".[dev]"
pytest -v
Links
- Node.js SDK — same API, Node.js edition
- PHP SDK — same API, PHP edition
- RevAddress API — managed USPS API with BYOK support
- RevAddress Docs — API reference and guides
- USPS v3 API Docs
- PyPI Package
License
MIT — see LICENSE.
Built by RevAddress — managed USPS API infrastructure for developers and businesses.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file usps_v3-1.0.4.tar.gz.
File metadata
- Download URL: usps_v3-1.0.4.tar.gz
- Upload date:
- Size: 20.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a2146768268259271879e1981cb6c998d06937c8bf14426e7029ae1fcdac928
|
|
| MD5 |
5bd3a038ee3e7fdb0c46b27f26462fec
|
|
| BLAKE2b-256 |
9e1d659e546f7a2e39a47c6b1161dbfc78bb09a247ae67c71fd3d6526397257f
|
File details
Details for the file usps_v3-1.0.4-py3-none-any.whl.
File metadata
- Download URL: usps_v3-1.0.4-py3-none-any.whl
- Upload date:
- Size: 21.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c369767d660599f4e709bc63dd6627b117338b3d5c73b4a2247a39affc53835
|
|
| MD5 |
79806d79f8c50d5ef3cdd0438dac1231
|
|
| BLAKE2b-256 |
3a19ec5809c21e761f5f2d7c6cdd8102cce2da8a8253df12fc74e45d4deb1df0
|