Skip to content

revereveal/usps-v3-node

Repository files navigation

usps-v3

npm License: MIT RevAddress

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-webtools or usps-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.

How this family fits together

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.

Need the managed lane instead of raw USPS auth plumbing?

If you're migrating from EasyPost or the legacy USPS Web Tools XML API and want a managed lane beside the raw SDKs:

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.

Install

npm install usps-v3

Quick Start

import { 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' }

API

Address Validation

// 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');

Package Tracking

const tracking = await client.tracking.track('9400111899223033005282');
console.log(tracking.statusCategory); // 'Delivered', 'In Transit', etc.

Rate Shopping

// 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,
});

Shipping Labels

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);

Delivery Estimates

const estimates = await client.standards.estimates('10001', '90210');
// [{ mailClass: 'PRIORITY_MAIL', daysToDelivery: 2 }, ...]

Drop-off Locations

const locations = await client.locations.dropoff({
  destinationZIP: '20500',
  mailClass: 'PRIORITY_MAIL',
});

Configuration

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
});

Error Handling

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

Token Management

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();

USPS Rate Limits

The v3 API defaults to 60 requests/hour. See our USPS rate limits guide for how to request an increase.

Migration from usps-webtools

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

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
  • 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.

USPS Developer Portal

  1. Register at developer.usps.com
  2. Create an application
  3. Get your Client ID and Client Secret
  4. For labels: complete COP Claims Linking for your CRID/MIDs

Links

License

MIT

Built by RevAddress — direct USPS API integration for developers.

About

USPS v3 REST API client for Node.js — address validation, tracking, labels, rates. Zero dependencies, full TypeScript.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors