USPS v3 REST API client — OAuth 2.0, address validation, tracking, labels, rates. Drop-in replacement for usps-webtools and usps-webtools-promise (retired January 2026).
Zero dependencies. Uses built-in fetch (Node 18+). Full TypeScript types included.
Migrating from
usps-webtoolsorusps-webtools-promise? Those packages use 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-webtools below.
Don't want to manage USPS credentials? RevAddress is the managed USPS lane for hosted OAuth, BYOK continuity, and a developer-facing surface without direct USPS auth plumbing. Get a free sandbox key — no credit card required.
USPS v3 is one delivery problem with four distinct lanes:
| Need | Best lane |
|---|---|
| Direct Python integration | revereveal/usps-v3 |
| Direct Node / TypeScript integration | revereveal/usps-v3-node |
| Direct PHP integration | revereveal/usps-v3-php |
| Managed OAuth, BYOK orchestration, and hosted developer surface | RevAddress |
The three SDK repos are sibling public packages, not duplicates. RevAddress is the managed product lane that sits beside them.
Human gate note: SDK installability and package health are separate from USPS enrollment and entitlement friction for production label/payment flows. The public SDK family can be healthy while USPS operator setup still blocks parts of live production rollout.
If you're migrating from EasyPost or the legacy USPS Web Tools XML API and want a managed lane beside the raw SDKs:
- Migration Guide — Step-by-step from XML to REST
- Endpoint Mapping — Every legacy endpoint mapped to v3
- RevAddress Docs — Hosted API docs and onboarding surface
Use the SDK when you want direct USPS integration in your own stack. Use RevAddress when you want the managed OAuth / BYOK / hosted-developer lane.
npm install usps-v3import { USPSClient } from 'usps-v3';
const client = new USPSClient({
clientId: process.env.USPS_CLIENT_ID,
clientSecret: process.env.USPS_CLIENT_SECRET,
});
// Validate an address
const result = await client.addresses.validate({
streetAddress: '1600 Pennsylvania Ave NW',
city: 'Washington',
state: 'DC',
ZIPCode: '20500',
});
console.log(result.address);
// { streetAddress: '1600 PENNSYLVANIA AVE NW', city: 'WASHINGTON', state: 'DC', ZIPCode: '20500' }// Validate and standardize
const validated = await client.addresses.validate({
streetAddress: '123 Main St',
city: 'New York',
state: 'NY',
});
// City/state lookup from ZIP
const info = await client.addresses.cityState('10001');const tracking = await client.tracking.track('9400111899223033005282');
console.log(tracking.statusCategory); // 'Delivered', 'In Transit', etc.// Domestic rates
const rates = await client.prices.domestic({
originZIPCode: '10001',
destinationZIPCode: '90210',
weight: 2.5,
});
// International rates
const intlRates = await client.prices.international({
originZIPCode: '10001',
destinationCountryCode: 'GB',
weight: 3.0,
});Label creation requires Payment Authorization credentials (CRID, MIDs, EPA). See our USPS CRID/MID enrollment guide for step-by-step setup.
const client = new USPSClient({
clientId: process.env.USPS_CLIENT_ID,
clientSecret: process.env.USPS_CLIENT_SECRET,
crid: process.env.USPS_CRID,
masterMid: process.env.USPS_MASTER_MID,
labelMid: process.env.USPS_LABEL_MID,
epaAccount: process.env.USPS_EPA_ACCOUNT,
});
const label = await client.labels.create({
fromAddress: {
streetAddress: '228 Park Ave S',
city: 'New York',
state: 'NY',
ZIPCode: '10003',
},
toAddress: {
streetAddress: '1600 Pennsylvania Ave NW',
city: 'Washington',
state: 'DC',
ZIPCode: '20500',
},
mailClass: 'PRIORITY_MAIL',
weight: 2.0,
});
console.log(label.trackingNumber);const estimates = await client.standards.estimates('10001', '90210');
// [{ mailClass: 'PRIORITY_MAIL', daysToDelivery: 2 }, ...]const locations = await client.locations.dropoff({
destinationZIP: '20500',
mailClass: 'PRIORITY_MAIL',
});const client = new USPSClient({
clientId: 'your-client-id', // or USPS_CLIENT_ID env var
clientSecret: 'your-client-secret', // or USPS_CLIENT_SECRET env var
baseUrl: 'https://apis.usps.com', // default
timeout: 30000, // ms, default
// For label creation:
crid: '...', // or USPS_CRID
masterMid: '...', // or USPS_MASTER_MID
labelMid: '...', // or USPS_LABEL_MID
epaAccount: '...', // or USPS_EPA_ACCOUNT
});import { USPSClient, RateLimitError, ValidationError, AuthError } from 'usps-v3';
try {
await client.addresses.validate({ streetAddress: '' });
} catch (err) {
if (err instanceof ValidationError) {
console.log(`Bad field: ${err.field}`);
} else if (err instanceof RateLimitError) {
console.log(`Retry after ${err.retryAfter}s`);
} else if (err instanceof AuthError) {
console.log('Check credentials');
}
}| Error Class | When |
|---|---|
ValidationError |
Invalid input parameters |
AuthError |
OAuth or Payment Auth failure |
RateLimitError |
429 from USPS (default: 60 req/hr) |
APIError |
USPS returned an error response |
NetworkError |
Connection timeout, DNS failure |
OAuth tokens are cached in memory and auto-refreshed 30 minutes before expiry.
// Check token state
console.log(client.tokenStatus);
// { hasOAuthToken: true, oauthExpiresIn: 27000, ... }
// Force refresh
await client.refreshTokens();
// Clean up
client.close();The v3 API defaults to 60 requests/hour. See our USPS rate limits guide for how to request an increase.
The usps-webtools and usps-webtools-promise npm packages target the retired USPS Web Tools XML API (shut down January 25, 2026). If you're using either package, here's how to migrate:
| usps-webtools | usps-v3 |
|---|---|
verify(address, callback) |
client.addresses.validate(address) |
zipCodeLookup(address, callback) |
client.addresses.cityState(zip) |
track(trackingNumber, callback) |
client.tracking.track(trackingNumber) |
rates(params, callback) |
client.prices.domestic(params) |
| USERID string auth | OAuth 2.0 (Client ID + Secret) |
| XML responses | JSON responses |
Key differences:
- OAuth 2.0 instead of USERID — register at developer.usps.com
- Address fields:
Address2(street) →streetAddress,Address1(apt) →secondaryAddress - Rate limits: ~60 req/hr default (old API had no practical limit)
- All responses are JSON (no XML parsing needed)
Full migration guide: USPS Web Tools to v3 REST | Endpoint mapping
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
- Managed OAuth + token lifecycle — stay out of USPS auth churn
- Rate-limit smoothing — reduce the practical pain of direct USPS limits without promising unproven throughput numbers
- BYOK support — bring your own USPS credentials when you need account continuity
- Hosted developer surface — use a managed lane instead of rebuilding USPS auth plumbing yourself
Get a free sandbox key — address validation, tracking, and rate shopping included. No credit card required.
- Register at developer.usps.com
- Create an application
- Get your Client ID and Client Secret
- For labels: complete COP Claims Linking for your CRID/MIDs
- Python SDK — sibling public SDK for Python
- PHP SDK — sibling public SDK for PHP
- RevAddress API — managed USPS API with BYOK support
- RevAddress Docs — API reference and guides
- RevAddress Pricing — current plan and packaging details
- USPS v3 API Docs
- npm Package
MIT
Built by RevAddress — direct USPS API integration for developers.