Adding parcel tracking to your Node.js application doesn’t have to be complicated. In this tutorial, you’ll build a working tracking system using the WhereParcel SDK — from installation to real-time webhook notifications.

Prerequisites

  • Node.js 18+ (the SDK uses native fetch)
  • A WhereParcel API key (get one free)

Step 1: Install the SDK

npm install whereparcel

The package has zero dependencies — it only uses Node.js built-in APIs.

Step 2: Initialize the Client

import { WhereParcel } from 'whereparcel';

const wp = new WhereParcel(
  process.env.WHEREPARCEL_API_KEY!,
  process.env.WHEREPARCEL_SECRET_KEY!
);

Store your credentials in environment variables. Never hardcode API keys in your source code.

Step 3: Track a Parcel

The simplest use case — track a single parcel by carrier code and tracking number:

const response = await wp.track([
  { carrier: 'us.usps', trackingNumber: '9400111899562537866361' },
]);

console.log(response.summary);
// { total: 1, success: 1, failed: 0, usageIncremented: 1 }

for (const result of response.results) {
  if (result.status === 'success') {
    console.log(`Status: ${result.data.deliveryStatus}`);
    // Status: in_transit
  }
}

Understanding Delivery Statuses

WhereParcel normalizes all carrier statuses into these values:

StatusDescription
pendingLabel created, not yet picked up
in_transitPackage is in transit
out_for_deliveryOut for delivery
deliveredSuccessfully delivered
failedDelivery attempt failed
returnedReturned to sender
cancelledShipment cancelled
unknownStatus could not be determined

Step 4: Track Multiple Parcels

For e-commerce platforms tracking hundreds of orders, use bulk tracking (up to 5 per request):

const response = await wp.track([
  { carrier: 'us.usps', trackingNumber: '9400111899562537866361' },
  { carrier: 'us.fedex', trackingNumber: '123456789012' },
  { carrier: 'us.ups', trackingNumber: '1Z999AA10123456784' },
]);

console.log(response.summary);
// { total: 3, success: 3, failed: 0, usageIncremented: 3 }

for (const result of response.results) {
  if (result.status === 'success') {
    console.log(`${result.carrier}: ${result.data.deliveryStatus}`);
  }
}

Step 5: Find the Right Carrier Code

Not sure which carrier code to use? The SDK can help:

// List all 500+ carriers
const allCarriers = await wp.getCarriers();

// List US carriers only
const usCarriers = await wp.getCarriersByCountry('us');
// ['us.fedex', 'us.ups', 'us.usps', ...]

// List supported countries
const countries = await wp.getCountries();
// ['kr', 'us', 'jp', 'cn', 'de', ...]

Carrier codes follow the format {country}.{carrier} — for example, us.fedex, kr.cj, jp.yamato.

Step 6: Set Up Webhooks

Instead of polling, let WhereParcel notify you when a package status changes:

6a. Create a Webhook Endpoint

const endpoint = await wp.createWebhookEndpoint({
  name: 'My App - Production',
  url: 'https://myapp.com/api/webhooks/tracking',
});

// Save endpoint.secret to verify webhook signatures later
console.log(endpoint.endpointId); // 'endpoint_abc123'
console.log(endpoint.secret);     // 'whsec_...'

6b. Register Parcels for Monitoring

await wp.registerWebhook({
  trackingItems: [
    { carrier: 'us.usps', trackingNumber: '9400111899562537866361' },
    { carrier: 'us.fedex', trackingNumber: '123456789012' },
  ],
  recurring: true,
  webhookEndpointId: endpoint.endpointId,
});

With recurring: true, WhereParcel will keep monitoring until the package is delivered, sending you updates at each status change.

6c. Handle Webhook Events

In your Express/Fastify/Next.js app, add a webhook handler:

app.post('/api/webhooks/tracking', (req, res) => {
  const { carrier, trackingNumber, deliveryStatus, events } = req.body;

  console.log(`${carrier} ${trackingNumber}: ${deliveryStatus}`);

  // Update your database, notify the customer, etc.

  res.status(200).json({ received: true });
});

Error Handling Best Practices

Always handle errors gracefully:

import {
  WhereParcel,
  AuthenticationError,
  RateLimitError,
  NotFoundError,
} from 'whereparcel';

try {
  const result = await wp.track([{ carrier: 'us.usps', trackingNumber: '...' }]);
} catch (error) {
  if (error instanceof AuthenticationError) {
    // Invalid API key — check your credentials
    console.error('Authentication failed');
  } else if (error instanceof RateLimitError) {
    // Too many requests — back off and retry
    const retryAfter = error.retryAfter ?? 60;
    console.error(`Rate limited. Retry in ${retryAfter}s`);
  } else if (error instanceof NotFoundError) {
    // Carrier or endpoint not found
    console.error('Not found');
  }
}

Complete Example: Express Tracking API

Here’s a minimal Express server that wraps WhereParcel:

import express from 'express';
import { WhereParcel } from 'whereparcel';

const app = express();
const wp = new WhereParcel(
  process.env.WHEREPARCEL_API_KEY!,
  process.env.WHEREPARCEL_SECRET_KEY!
);

app.get('/track/:carrier/:trackingNumber', async (req, res) => {
  const { carrier, trackingNumber } = req.params;
  const result = await wp.track([{ carrier, trackingNumber }]);
  res.json(result);
});

app.listen(3000, () => console.log('Tracking server running on :3000'));

Test it:

curl http://localhost:3000/track/us.usps/9400111899562537866361

Next Steps

Have questions? Visit our community page.