The USPS Tracking API: How To Track Packages

October 3, 2019

As you might expect for a government organization, USPS has an old-school XML API that is publicly available.

In this short update I'll show you how to track a package using the USPS tracking API.

The first step is registering for a free developer account with USPS.

After registration, there's a short wait and you'll likely receive an email with a user ID that may look something like "123ORGNAME4567". USPS doesn't use anything fancy like API keys - your User ID is your API key.

USPS Tracking API with NodeJs

Using NodeJs, here's how you might track a package:

const got = require('got')
const xml2json = require('xml2json')
const track = async () => {
  const BASE_URI = 'http://production.shippingapis.com/ShippingAPI.dll?API=TrackV2'
  const xml = xml2json.toXml({
    TrackRequest: {
      USERID: process.env.USPS_USER_ID
      TrackID: [{ID: process.env.TEST_TRACKING_NUMBER}]
    }
  })
  let { body } = await got(`${BASE_URI}&XML=${encodeURIComponent(xml)}`)
  let data = JSON.parse(xml2json.toJson(body))
  return data
}
track().then(console.log.bind(console))

In the above code snippet, I'm using got but you could just as easily use node-fetch.

To make requests against USPS' API, you essentially need to provide URL-encoded xml in the query string. So, for example:

{
  TrackRequest: {
    USERID: "XXXXX",
    TrackId: [{ID: "92748999984327000003259997"}]
  }
}

Becomes the following with xml2json conversion:

<TrackRequest USERID="XXXXX">
  <TrackId ID="92748999984327000003259997"></TrackId>
</TrackRequest> 

Using USPS' Postal Code API

Here's how you might perform zip code lookups using the USPS Postal Code API.

const got = require('got')
const xml2json = require('xml2json')
const postalCodeLookup = async (zipCode) => { 
  const BASE_URI = 'http://production.shippingapis.com/ShippingAPITest.dll?API=CityStateLookup'
  const xml = `
  <CityStateLookupRequest USERID="XXXXX">
    <ZipCode ID="0">
      <Zip5>${zipCode}</Zip5>
    </ZipCode>
  </CityStateLookupRequest>
  `
  const url = `${BASE_URI}&XML=${encodeURIComponent(xml)}`
  let { body } = await got(url)
  return JSON.parse(xml2json.toJson(body))
}
postalCodeLookup(99501).then(console.log.bind(console))

Further Reading