Skip to content
All Posts
Reference

USPS Web Tools to v3 REST API: Complete Endpoint Mapping

·Updated ·12 min read·By RevAddress·Reference

USPS retired the Web Tools XML API on January 25, 2026. Every legacy XML surface now has a REST equivalent on a different host, with a different auth model and, in several places, different field semantics. This is the mapping reference: which v3 route replaces your legacy call, and what changes about the call besides its URL.

Every route below is checked against the published USPS v3 OpenAPI specifications rather than reproduced from migration folklore. Where the commonly-repeated answer is wrong, that is called out.

Master endpoint mapping

Address APIs

Web Tools XML API v3 REST endpoint Method Notes
AddressValidateRequest /addresses/v3/address GET Query params, not an XML body. DPV comes back in additionalInfo
CityStateLookupRequest /addresses/v3/city-state GET ZIP to city and state
ZipCodeLookupRequest /addresses/v3/zipcode GET Returns ZIP+4

Tracking APIs

Web Tools XML API v3 REST endpoint Method Notes
TrackFieldRequest /tracking/v3/tracking/{trackingNumber} GET Tracking number is a path parameter now
TrackConfirmRequest /tracking/v3/tracking/{trackingNumber} GET Unified. Same route as TrackField

Shipping and label APIs

Web Tools XML API v3 REST endpoint Method Notes
eVS (Express Mail) /labels/v3/label POST Needs a Payment Authorization token
eVS (Priority Mail) /labels/v3/label POST Same route, different mailClass
eVS (Ground Advantage) /labels/v3/label POST Replaces First-Class Package Service
eVSCancel /labels/v3/label/{trackingNumber} DELETE Cancel or refund. See the note below

Pricing APIs

Web Tools XML API v3 REST endpoint Method Notes
RateV4Request /prices/v3/base-rates/search POST JSON body replaces the XML envelope. One mail class per call
IntlRateV2Request /international-prices/v3/base-rates/search POST Same shape, ISO alpha-2 country codes

The base path is prices, not domestic-prices, and the operation is a POST to a /search route rather than a GET. Both halves of that get published wrong regularly. /prices/v3/total-rates/search is the sibling route when you want totals including extra services rather than base rates alone.

Service standards and locations

Web Tools XML API v3 REST endpoint Method Notes
SDCGetLocationsRequest /service-standards/v3/estimates GET Delivery estimates by origin and destination
POLocatorRequest /locations/v3/post-office-locations GET Post offices by ZIP or coordinates

The locations route is post-office-locations, not post-offices. The same API also serves /locations/v3/dropoff-locations and /locations/v3/parcel-locker-locations, which have no Web Tools equivalent at all.

Authentication: before and after

Web Tools embedded a plain-text USERID in every XML request body. No scopes, no expiry, no rotation. The v3 API uses OAuth 2.0 client credentials, with tokens that last 8 hours.

Before — Web Tools authxml
POST https://secure.shippingapis.com/ShippingAPI.dll?API=Verify

<AddressValidateRequest USERID="YOUR_USERID">
<Address>
  <Address1>Apt 2</Address1>
  <Address2>1600 Pennsylvania Ave</Address2>
</Address>
</AddressValidateRequest>

<!-- USERID in plain text. No expiry. No scopes. No rotation. -->
After — OAuth 2.0bash
# Step 1: get a token (8-hour lifetime, expires_in 28800)
curl -X POST "https://apis.usps.com/oauth2/v3/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"

# Step 2: send it as a Bearer token
curl "https://apis.usps.com/addresses/v3/address?streetAddress=1600+Pennsylvania+Ave+NW&city=Washington&state=DC&ZIPCode=20500" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Cache that token. A token request spends one call against the same 60-per-hour budget as the address lookup it authorizes, so refetching per call halves your throughput.

Key gotchas

These are the migration landmines. Each one has taken down a production system.

01. The rate limit is 60 an hour, and it is shared

Web Tools had no meaningful documented limit. The v3 API allows 60 requests an hour per application, and address validation, tracking, pricing, and labels all draw on the same window. Token fetches count too. A store doing 50 orders a day will cross it during peak hours. You can request an increase; plan for the constraint regardless.

02. Label creation needs two tokens, in two different headers

Labels are the only endpoint family that needs a second authorization token: the standard OAuth Bearer token plus a Payment Authorization token tied to your CRID and MID.

The two-token flowbash
# 1. Standard OAuth token
POST https://apis.usps.com/oauth2/v3/token
   grant_type=client_credentials

# 2. Payment Authorization token
POST https://apis.usps.com/payments/v3/payment-authorization
   Authorization: Bearer {standard_token}
   {
     "roles": [
       { "roleName": "PAYER",
         "CRID": "YOUR_CRID",
         "MID": "YOUR_MID",
         "accountType": "EPS",
         "accountNumber": "YOUR_EPS_ACCOUNT" }
     ]
   }

# 3. Create the label with BOTH, in separate headers
POST https://apis.usps.com/labels/v3/label
   Authorization: Bearer {standard_token}
   X-Payment-Authorization-Token: {payment_token}

Two details in that flow are commonly published wrong. The payment endpoint is /payments/v3/payment-authorization, not a payment-authorization/v3/payment-token route. And the header is X-Payment-Authorization-Token, not X-Payment-Authorization. The USPS Labels specification marks that header required on label creation, reprint, and cancellation. Put the token in the JSON body instead and the header is simply absent, which USPS reports as an authorization failure that reads like a credential problem when your credentials are fine.

03. Address1 and Address2 semantics are reversed

The single most common migration bug.

Field mapping — do not get this wrongjson
// Web Tools XML (reversed semantics)
// <Address1>Apt 2</Address1>              <- secondary
// <Address2>1600 Penn Ave</Address2>      <- primary street

// v3 REST JSON (plain semantics)
{
"streetAddress": "1600 Penn Ave",
"secondaryAddress": "Apt 2"
}

// Map Address1 -> streetAddress and every apartment
// number becomes the street. It fails silently.

04. DPV data moved, it did not disappear

The field is still called DPVConfirmation. What changed is where it sits: the v3 response nests it inside an additionalInfo object alongside deliveryPoint, carrierRoute, countyName, congressDistrict, footnotes, vacant, business, and DPVCMRA, rather than putting it beside the standardized address lines. Code that reaches for it at the top level of the address object finds nothing and reads it as “not confirmed.”

The codes themselves are worth restating because D and S are published backwards constantly: Y both primary and secondary confirmed, D primary confirmed with secondary missing, S primary confirmed with secondary present but unconfirmed, N neither confirmed.

05. Cancel and refund are different operations

DELETE /labels/v3/label/{trackingNumber} cancels a label while no Shipping Services File has been created for it. Once one exists, the same call becomes a refund request and returns a disputeId you use to track the outcome. USPS issues one unique disputeId per CRID per day, so resubmitting the same label the same day is rejected rather than queued.

There is no simple 24-hour void window, which is the number most migration guides print. The trigger is the Shipping Services File, not the clock.

06. New base URLs

Environment Web Tools v3 REST
Production secure.shippingapis.com apis.usps.com
Testing stg-secure.shippingapis.com apis-tem.usps.com

The test environment takes your production credentials rather than a separate sandbox key pair, and the same product entitlements apply there. A flow that fails in TEM for lack of a granted product will fail identically in production.

07. One endpoint became many routes

Web Tools used an API name per operation (?API=Verify, ?API=CityStateLookup) but every one of them hit the same ShippingAPI.dll. The v3 API gives each resource its own path. Do not port the old dispatcher; map each operation to its dedicated route.

08. Migrating the code is no longer the last step

This one post-dates the shutdown by six months. Since August 1, 2026 the Addresses API requires a signed license agreement, and USPS states that “customers who did not complete onboarding no longer have access to the Addresses API.” A correctly mapped, correctly authenticated v3 integration can still return 401 on every address call. The license is requested through the Business Portal at cop.usps.com under My Account → API Licenses → Add an Addresses API License, signed by DocuSign, and countersigned by USPS on no published schedule. The enrollment guide walks it end to end.

Quick reference: field name changes

Web Tools XML field v3 REST JSON field Watch out
Address1 secondaryAddress Semantics reversed
Address2 streetAddress Semantics reversed
Zip5 ZIPCode Capital ZIP
Zip4 ZIPPlus4 Capital ZIP, Plus4 suffix
FirmName firm Simplified
DPVConfirmation DPVConfirmation, inside additionalInfo Same name, moved one level down
USERID attribute Authorization header Not in the body anymore

Where this leaves you

The mapping is mechanical. The parts that are not mechanical are the 60-per-hour ceiling, the two-token label flow, and the license, and those are what actually decide whether a migration ships.

RevAddress runs the machinery against your own USPS credentials: the OAuth lifecycle, the X-Payment-Authorization-Token header, Retry-After handling, caching, and retries, with credentials encrypted at rest. DPV, ZIP+4, rates, tracking, and labels are USPS data and bill on your license, on every plan. Census-based standardization, geocoding, and address extract need no USPS license at all.

Start here

Questions

What replaced AddressValidateRequest in the USPS v3 API?
GET /addresses/v3/address on the apis.usps.com host. It takes query parameters instead of an XML body, returns JSON, and carries DPV data in the additionalInfo object of the response rather than requiring a separate call.
What replaced RateV4Request?
POST /prices/v3/base-rates/search, with international pricing at POST /international-prices/v3/base-rates/search. Note the base path is prices, not domestic-prices, and the operation is a POST to a search route rather than a GET.
How does label creation authorize in v3?
With two tokens. The standard OAuth Bearer token goes in the Authorization header, and a Payment Authorization token from POST /payments/v3/payment-authorization goes in the X-Payment-Authorization-Token header. Sending the second one in the JSON body is the most common cause of a 401 on a label call.
Can I still cancel a USPS label after creating it?
A label can be canceled while no Shipping Services File has been created for it. Once one exists, you submit a refund request instead, which returns a disputeId for tracking. USPS issues one unique disputeId per CRID per day, so duplicate same-day submissions for the same label are rejected.
Are Address1 and Address2 really reversed?
Yes, and it is the single most common migration bug. In Web Tools XML, Address1 was the secondary line such as an apartment or suite, and Address2 was the primary street address. In v3, streetAddress is primary and secondaryAddress is secondary. Mapping Address1 to streetAddress turns every apartment number into a street.