Mock shipping & tracking API β€” fake shipments and tracking events, no signup

You're building the "Where's my order?" page: a status badge, a tracking timeline, an ETA, maybe a map pin. You need shipping-shaped JSON β€” and every real shipping API puts an account between you and your first fake response. Verified with plain unauthenticated curls, September 2026:

Those test modes exist to verify their integration β€” carrier accounts, label purchases, rate quotes. If all you need today is a stateful shipping-shaped API for a frontend, a demo, a workshop, or CI, this guide builds one in a single paste: hosted, CORS-open, HTTPS, no account, no key.

Building your tracking timeline, status badges, delivery-notification logic, or a portfolio e-commerce app? That's this page. Buying real labels, validating addresses, quoting real rates? Use a real provider; see the honest comparison below.

1. A shipping-shaped mock in one paste

BASE=https://mockbird.mockbird.workers.dev
P=$(curl -s -X POST $BASE/api/projects -H 'content-type: application/json' \
     -d '{"name":"fake-shipping","blank":true}')
PID=$(echo $P | sed 's/.*"id": *"\([^"]*\)".*/\1/')
KEY=$(echo $P | sed 's/.*"adminKey": *"\([^"]*\)".*/\1/')

curl -s -X POST $BASE/api/projects/$PID/resources -H "x-admin-key: $KEY" \
  -H 'content-type: application/json' -d '{
  "name":"shipments",
  "fields":[
    {"name":"tracking_number","type":"uuid"},
    {"name":"carrier","type":"oneOf","values":["usps","ups","fedex","dhl_express"]},
    {"name":"service","type":"oneOf","values":["ground","two_day","overnight","international"]},
    {"name":"status","type":"oneOf","values":["pre_transit","in_transit","out_for_delivery","delivered","exception"]},
    {"name":"origin_city","type":"city"},
    {"name":"destination_city","type":"city"},
    {"name":"eta","type":"futureDate"},
    {"name":"weight_oz","type":"number"}
  ],
  "seed":8
}'

curl -s -X POST $BASE/api/projects/$PID/resources -H "x-admin-key: $KEY" \
  -H 'content-type: application/json' -d '{
  "name":"tracking_events",
  "fields":[
    {"name":"shipmentId","type":"oneOf","values":[1,2,3,4,5,6,7,8]},
    {"name":"status","type":"oneOf","values":["pre_transit","in_transit","out_for_delivery","delivered","exception"]},
    {"name":"location","type":"city"},
    {"name":"description","type":"sentence"},
    {"name":"ts","type":"pastDate"}
  ],
  "seed":30
}'

Two tricks worth stealing: shipmentId is a numeric oneOf [1..8], so every seeded scan points at a shipment that actually exists β€” no dangling joins β€” and the vocabulary is the industry's own (pre_transit, out_for_delivery, exception are the states Shippo/EasyPost use), so a later swap to real data touches less code.

A shipment looks like this (live output, IDs will differ):

curl "https://mockbird.mockbird.workers.dev/m/<PID>/shipments/2"
{
  "id": 2,
  "tracking_number": "b5f3448b-d1e1-43c3-8c26-2a26370bfb5b",
  "carrier": "dhl_express",
  "service": "ground",
  "status": "delivered",
  "origin_city": "Nairobi",
  "destination_city": "Zagreb",
  "eta": "2026-12-10T01:46:33.772Z",
  "weight_oz": 206
}

2. The queries a tracking page actually makes

# the tracking timeline for one shipment (json-server-style nested route)
curl "$BASE/m/$PID/shipments/2/tracking_events"

# look a shipment up by its tracking number (exact-match field filter)
curl "$BASE/m/$PID/shipments?tracking_number=b5f3448b-d1e1-43c3-8c26-2a26370bfb5b"

# every delivered shipment / every exception to alert on
curl "$BASE/m/$PID/shipments?status=delivered"
curl "$BASE/m/$PID/shipments?status=exception"

# newest scans first, joined to their shipment
curl "$BASE/m/$PID/tracking_events?sortBy=ts&order=desc&limit=5&_expand=shipment"

Range filters compose too β€” ?ts_gte=2026-08-01 for "scans since August", ?weight_oz_gte=160 for heavy parcels. Need CSV for a spreadsheet demo? ?mock_format=csv&select=carrier,status,eta returns the same list as RFC-4180 CSV.

3. It's stateful β€” play the carrier

The real test of a tracking UI is change: a new scan arrives, the status flips, the timeline grows. These are real writes, visible to every subsequent read:

# a new carrier scan comes in…
curl -s -X POST $BASE/m/$PID/tracking_events -H 'content-type: application/json' \
  -d '{"shipmentId":2,"status":"delivered","location":"Zagreb",
       "description":"Delivered, signed by resident","ts":"2026-09-16T04:00:00Z"}'
# β†’ {"id": 31, …}

# …and the shipment itself flips to delivered
curl -s -X PATCH $BASE/m/$PID/shipments/2 -H 'content-type: application/json' \
  -d '{"status":"delivered"}'

curl "$BASE/m/$PID/shipments/2/tracking_events"   # timeline now includes scan 31

4. A public /track/:number endpoint

Carrier tracking pages accept any number in the URL. One custom route gives you the same shape β€” templated per request, no resource needed:

curl -s -X POST $BASE/api/projects/$PID/routes -H "x-admin-key: $KEY" \
  -H 'content-type: application/json' -d '{
  "method":"GET","path":"/track/:number",
  "body":{"tracking_number":"{{params.number}}","carrier":"usps",
          "status":"in_transit","checked_at":"{{now}}"}
}'

curl "$BASE/m/$PID/track/9405511899223197428490"
{
  "tracking_number": "9405511899223197428490",
  "carrier": "usps",
  "status": "in_transit",
  "checked_at": "2026-09-16T03:47:05.208Z"
}

5. Simulate what carriers actually do: flake

Real tracking endpoints rate-limit, time out, and 503 at peak season β€” exactly what your retry/backoff and stale-data UI need to survive. Deterministically:

# first two polls fail, third succeeds β€” assert your retry logic rides it out
curl -i "$BASE/m/$PID/shipments/2?mock_seq=503,503,200"

# a slow carrier: 2 seconds before the response
curl "$BASE/m/$PID/track/TEST123?mock_delay=2000"

# peak-season chaos: 30% of requests randomly fail
curl "$BASE/m/$PID/tracking_events?mock_chaos=0.3"

mock_seq is per-client and resettable β€” full recipes in testing loading & error states.

6. Webhooks β€” the carrier-push stand-in

EasyPost and Shippo push tracking updates to your server by webhook; so does Mockbird. Register a URL and every created/updated/deleted record fires a signed POST (X-Mockbird-Signature: sha256=…, HMAC of the raw body) β€” so the code path that reacts to "package moved" runs for real in dev and CI:

curl -s -X PUT $BASE/api/projects/$PID/webhook -H "x-admin-key: $KEY" \
  -H 'content-type: application/json' -d '{"url":"https://your-app.example.com/hooks/tracking"}'

# then play the carrier: POST a tracking_event (section 3) β†’ your endpoint
# receives a signed tracking_events.created delivery

Verification snippet and the queryable delivery log in sending test webhooks.

Shipping-API concern β†’ Mockbird

You wantedShippo / EasyPost / ShipEngine / 17TRACKMockbird
First request without an accountβœ— signup + API key, even for test modeβœ” one anonymous curl
Call it straight from a browserβœ— secret keys β†’ backend requiredβœ” CORS-open GETs
Your own statuses, fields, edge casesβ–³ their schemas, their test fixturesβœ” it's your data β€” POST/PATCH anything
An exception shipment on demandβ–³ special test tracking numbersβœ” seed it, or PATCH any record
Deterministic latency & failure sequencesβœ—βœ” mock_delay, mock_seq, chaos
Reset to a known dataset per testβ–³ varies by providerβœ” snapshots
Buy real labels, quote real rates, track real parcelsβœ” that's their jobβœ— fake by design

Honest comparison β€” where the real providers win

The clean split: Mockbird for the order-tracking frontend, demos, portfolio projects, and CI. A real provider the moment code touches labels, rates, or real parcels. They compose β€” point your app at the mock in dev via an env base URL, the real API in prod.

Notes & limits

Create yours

The paste block in section 1 is the whole setup β€” or open the dashboard and click it together. The same project also serves GraphQL, exports OpenAPI + TypeScript types, and ejects to db.json anytime β€” no lock-in.

⚑ Skip the terminal: this link creates a live, seeded e-commerce backend (products, orders, customers, reviews) in the dashboard β€” real URL, data browser already open, no signup. Or import your own OpenAPI spec, db.json, CSV, Postman collection, or HAR and mock your exact shapes.