This is a focused setup guide for the WhereParcel multi-carrier tracking API. The goal: from zero to a working production-shaped integration in five minutes, with code examples in four languages and a clear production checklist at the end.
If you just want a TL;DR, jump to the setup checklist at the bottom.
What You’ll Have at the End
- An API key tested against a live request
- A multi-carrier lookup that works across USPS, UPS, FedEx, DHL, and 60+ live carriers (more on request)
- Auto-detection so you don’t hardcode carrier names
- A webhook listener for push status updates
- A production-ready error and retry pattern
Step 1 — Sign Up and Get Your Key (1 min)
Go to whereparcel.com, sign up with email, and open your dashboard.
Create a new API key from /dashboard/api-keys. Your key looks like:
wp_live_a1b2c3d4e5f6g7h8i9j0
Treat it like a password. Never put it in client-side JavaScript or commit it to a public repo. Use environment variables:
export WP_API_KEY="wp_live_a1b2c3d4e5f6g7h8i9j0"
The 7-day free trial activates immediately, so you can test against the real API. If you want extended free usage, the ambassador program gives you 3 months of the Starter plan free for one short blog post mentioning WhereParcel.
Step 2 — Your First Tracking Request (2 min)
The single endpoint you need is POST /v2/track. Pick the language you actually use.
cURL
curl -X POST https://api.whereparcel.com/v2/track \
-H "Authorization: Bearer $WP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"trackingItems": [
{ "carrier": "us.usps", "trackingNumber": "9400111899223197428490" }
]
}'
Node.js (fetch)
const res = await fetch('https://api.whereparcel.com/v2/track', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.WP_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
trackingItems: [
{ carrier: 'us.usps', trackingNumber: '9400111899223197428490' },
],
}),
});
const data = await res.json();
console.log(data);
Python (requests)
import os, requests
res = requests.post(
'https://api.whereparcel.com/v2/track',
headers={'Authorization': f"Bearer {os.environ['WP_API_KEY']}"},
json={
'trackingItems': [
{'carrier': 'us.usps', 'trackingNumber': '9400111899223197428490'}
]
},
)
print(res.json())
Go (net/http)
body := strings.NewReader(`{
"trackingItems": [
{"carrier": "us.usps", "trackingNumber": "9400111899223197428490"}
]
}`)
req, _ := http.NewRequest("POST", "https://api.whereparcel.com/v2/track", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("WP_API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
What You Get Back
{
"success": true,
"data": [
{
"carrier": "us.usps",
"carrierName": "USPS",
"trackingNumber": "9400111899223197428490",
"status": "in_transit",
"lastUpdated": "2026-05-04T12:00:00Z",
"events": [
{ "time": "2026-05-04T12:00:00Z", "location": "Los Angeles, CA", "description": "Out for delivery" }
]
}
]
}
The schema is identical across all 64+ live carriers (and new ones added on request). Status enums are normalized — no more switching on each carrier’s quirky strings.
Step 3 — Auto-Detection (3 min)
You usually don’t know which carrier owns a number until you ask. Pass carrier: "auto" and the API figures it out:
{
trackingItems: [
{ carrier: 'auto', trackingNumber: '1Z999AA10123456784' }, // UPS
{ carrier: 'auto', trackingNumber: 'EE123456785US' }, // USPS S10
{ carrier: 'auto', trackingNumber: 'JJD01234567890' }, // DHL
]
}
The response tells you which carrier was matched. This single feature is usually the reason teams switch from carrier-specific APIs to a unified tracking API — there’s no longer any per-carrier branching code in your codebase.
You can also batch up to 5 numbers per request, which is the right move for any background job that processes recent shipments in bulk.
Step 4 — Webhooks for Push Updates (4 min)
Polling every shipment every hour is wasteful and slow. Webhooks reverse the flow: WhereParcel calls you when a shipment’s status changes.
Register Your Webhook
In the dashboard, add an endpoint URL like https://yourapp.com/webhooks/whereparcel and pick the events you care about (status changes, delivered, exceptions).
Receive It
// Express example
app.post('/webhooks/whereparcel', express.json(), (req, res) => {
const { trackingNumber, carrier, status, events } = req.body;
// Persist the update
await db.shipments.update({ trackingNumber }, { status, events });
res.status(200).send('ok');
});
Two production essentials:
- Verify the signature — every webhook includes an
X-WhereParcel-Signatureheader. Compute the HMAC-SHA256 of the raw body using your webhook secret and reject mismatches. - Respond 2xx fast — do the heavy work in a queue. WhereParcel uses exponential-backoff retries on non-2xx responses, but slow handlers eat into your timeout budget.
Step 5 — Production Checklist (5 min) {#production-checklist}
A working request is not a working integration. Run through this before you ship:
- API key in env vars only. Never in source, never in front-end bundles
- Auto-detection in place so you don’t have a per-carrier
if/elseladder - Idempotency keys on any code path that creates shipments
- Webhook signature verification
- Webhook handler queues work rather than blocking on heavy DB writes
- Polling fallback for environments where you can’t receive webhooks
- Rate-limit aware retries — Starter is 30 req/min, Pro is 60, Business is 200; back off on 429
- Status enum mapping to your internal model (e.g.
in_transit→SHIPPED_IN_PROGRESS) - Error logging with the request ID that the API returns in headers
- Sandbox vs production keys kept in separate environments
Common Issues and How to Fix Them
| Symptom | Likely cause | Fix |
|---|---|---|
| 401 Unauthorized | Key missing the Bearer prefix | Add Authorization: Bearer YOUR_KEY |
| 429 Too Many Requests | Burst exceeded plan rate limit | Add exponential backoff or upgrade plan |
Status stuck on pending | Carrier hasn’t scanned the parcel yet | Poll or re-check after several hours; not an API issue |
carrier: "auto" returns wrong carrier | Tracking number shape collides between carriers | Pass the carrier explicitly when you know it |
| Webhook not firing | Wrong URL, dev server unreachable, or event filter excludes the change | Check dashboard logs and signature verification |
Next Steps
- Full API reference — every endpoint, every response field
- Best Parcel Tracking API 2026 Comparison — how WhereParcel compares to AfterShip, 17TRACK, Tracktry, and Parcellab
- Webhook best practices
- API rate limiting best practices
If you got stuck anywhere in the five minutes, ping support from the dashboard — we usually answer same-day.