USPS Web Tools to v3 REST API: Complete Endpoint Mapping
Updated 12 min read By RevAddress
Topics: Web Tools migration, USPS v3, 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.
Every route below is checked against the published USPS v3 OpenAPI specifications.
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. /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 from USERID to OAuth 2.0
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.
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. -->
# 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.
Eight behavior changes from Web Tools to v3
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. You can request an increase and build for the default from day one.
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.
# 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 carry exact names. 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 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
// 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 into additionalInfo
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, per the USPS specification: 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.
The trigger is the Shipping Services File, not a 24-hour 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. The Addresses API license since August 1, 2026
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.” Until it is linked, a correctly mapped, correctly authenticated v3 integration returns 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.
Field name changes from XML to JSON
| Web Tools XML field | v3 REST JSON field | Change |
|---|---|---|
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 |
The machinery RevAddress runs on your USPS credentials
The mapping is mechanical; the 60-per-hour ceiling, the two-token label flow, and the license take infrastructure and enrollment.
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
- USPS Web Tools shutdown: what broke on January 25 and the migration paths
- Migration checklist: the step-by-step version
- OAuth troubleshooting: every 401, 403, and 429 with its fix
- CRID and MID enrollment: the license, the EPA, and COP claims linking
- Rate limit strategies: caching and queueing past 60 an hour
- Get a free API key: 1,000 requests a month, no credit card, no USPS license
- Open-source clients: Python and Node on
usps-v3, PHP onrevaddress/usps-v3-php
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 returns 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. 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.
Read next
-
USPS Web Tools Shut Down on January 25, 2026: What Broke and the Fastest Way to the v3 API
USPS retired Web Tools on January 25, 2026. If ShippingAPI.dll, USERID, or secure.shippingapis.com is failing, map the XML route to v3 REST here.
-
USPS Web Tools Migration Checklist (2026)
A numbered checklist for moving off USPS Web Tools XML: endpoint map, the license now required, OAuth, field mapping, error mapping, and the cutover.
-
USPS v3 OAuth Troubleshooting: Every Error and How to Fix It
401, 403, and 429 from USPS v3, with the exact fix for each, including the Addresses API license that has gated address calls since August 1, 2026.