Comparing lastscanned vs. direct carrier calls, AfterShip, EasyPost, Ship24 & 17TRACK
When building package tracking into a SaaS product, customer support workflow, order-status portal, or AI agent, engineering teams typically evaluate two options:
Calling carrier websites or official carrier APIs directly from their own backend (Cloudflare Workers, Vercel Functions, AWS Lambda, Fly.io).
Buying a multi-carrier tracking aggregator (AfterShip, EasyPost, Ship24, or 17TRACK).
This page breaks down the concrete technical obstacles of calling 31 carriers directly from serverless functions, followed by a head-to-head architecture and pricing comparison against legacy tracking aggregators.
If you try to fetch() carrier tracking endpoints directly from a serverless or edge runtime (Cloudflare Workers, Vercel Functions, AWS Lambda, Fly.io, or a Node.js container on a cloud provider), requests fail immediately across both undocumented web endpoints and official carrier developer portals:
Carrier
What happens when your serverless function calls the carrier directly
Undocumented web API (webapis.ups.com/track/api/Track/GetStatus): Protected by Akamai Bot Manager (403 Forbidden on datacenter IPs and Node/Undici TLS fingerprints) and requires a paired GetCSRFToken handshake (X-XSRF-TOKEN-ST header + session cookies). Official UPS Developer Portal: Requires OAuth 2.0 client credentials tied to a 6-character UPS shipper account number.
One stateless GET request with Authorization: Bearer lsk_live_... returns normalized UTC + local timestamps, signedBy, service, and scan events—no UPS account required.
Undocumented web API & api.fedex.com/track/v2/shipments: Akamai Bot Manager sensor checks reject cloud/datacenter requests with 403, while the official FedEx Developer Portal requires OAuth 2.0 token refresh loops, project validation tests, and production key approval.
Auto-detects 12-, 15-, 20-, and 96… 22-digit FedEx barcodes in Pass 1 and returns the full scan history in one synchronous JSON response.
Public tracker (tools.usps.com): Akamai Bot Manager blocks serverless datacenter IPs with 403 or blank challenge pages. Official USPS v3 API: Requires OAuth 2.0 + Customer Onboarding Portal (COPRA) enrollment (Mailer ID / CRID), and still returns "Pre-Shipment: Picked Up by Shipping Partner, USPS Awaiting Item" ("USPS Currently Awaiting Package") for 3–7 days on 92… consolidator labels.
Tracks all 92…–95… and …US S10 numbers with zero USPS enrollment—and lets you pass ?carrier=osm or ?carrier=pitneybowes on 92… consolidator barcodes to retrieve live middle-mile sort scans before USPS acceptance.
Fragmented portals & rate limits: DHL splits tracking across express, ecommerce, and parcel-de divisions, requires a DHL Developer Portal API key (DHL-API-Key) with strict default daily quotas, and returns deeply nested division-specific schemas.
Validates 10-digit Mod-7 (dhlExpress) and S10 …DE check digits, routes across Express, eCommerce, and Paket automatically, and normalizes every scan into one schema.
Datacenter IP blocks (t.lasership.com/OrderEvents): Blocks automated datacenter requests and requires separate legacy LaserShip vs. OnTrac format handling.
Auto-detects both OnTrac (C/D + 14 digits) and LaserShip (1LS…, LX…) formats and returns normalized UTC and local scan timestamps.
Firebase App Check gate (graph.shipveho.com/graphql): Rejects requests with 401/403 unless accompanied by a live x-firebase-appcheck token minted via reCAPTCHA Enterprise (6Lf5dJ4pAAAAAM5213981b76-48e0-a6a8-575b0e5d1). Official Veho Packages API (api.shipveho.com) restricts tracking details unless your merchant API key created the order.
Tracks any VH… parcel (and shipper references via ?carrier=veho) with one API key—no Veho shipper contract or App Check token required.
WAF challenges & shipper-only portals: Purolator sits behind AWS WAF challenges and SOAP/REST contract keys; Canada Post requires Developer Program credentials; Intelcom / Dragonfly (INTLCM…) has no self-serve public developer portal.
Validates 16-digit GS1 Mod-10 (gs1) and S10 …CA numbers, supports Purolator 3L+9D and ?carrier=purolator 12-digit PINs, and auto-detects INTLCM… Dragonfly parcels across Canada and Australia.
Proprietary payloads & proof-of-work gates: SpeedX encodes tracking payloads in base64 proto-JSON; Sendle's 2026 platform requires solving a cryptographic SHA-256 proof-of-work challenge (salt:nonce zero-bit check) on every lookup; TForce only renders year-less HTML tables; UniUni and GOFO offer no public recipient API keys.
Decodes every payload, solves Sendle's proof-of-work challenge, resolves regional timezones and check digits, and returns a single TrackingResult JSON shape.
Signature headers, IP bans & missing handoff numbers: CNE requires custom MD5 request signatures and blocks shared IPs (ReturnValue: -5555); SunYou wraps responses in JSONP with mislabeled +08:00 destination offsets; UBI mixes duplicate partner scans; merchant APIs require shipper accounts that created the waybill.
Auto-detects all 8 cross-border formats, cleans up timezone offsets, and extracts the destination carrier and final-mile tracking number into message (e.g. "Handed to USPS as 9261..." or "Handed to Australia Post as 33X...").
Instead of maintaining 31 regex matchers, 4 check-digit validators, per-carrier OAuth token caches, CSRF handshakes, and 31 response parsers in your serverless function—only to hit 403 Forbidden from a cloud IP—your backend makes a single fetch() call:
// One synchronous GET call from any Cloudflare Worker, Vercel Function, or AWS Lambdaconst res = await fetch( `https://api.lastscanned.com/v1/track/${encodeURIComponent(trackingNumber)}`, { headers: { Authorization: `Bearer ${process.env.LASTSCANNED_API_KEY}`, }, },);const pkg = await res.json();// pkg.carrier -> "ups" | "usps" | "fedex" | "speedx" | "uniuni" | ... (31 carriers)// pkg.status -> "label_created" | "in_transit" | "out_for_delivery" | "delivered" | "exception" | "returned" | "unknown"// pkg.estimatedDelivery -> "2026-10-28" (or null)// pkg.message -> "Handed to UniUni as UUS5BM1269395824723" (on cross-border handoffs)// pkg.events -> Chronological scan array with UTC `timestamp` and local `localTime`
Most multi-carrier tracking APIs were designed around asynchronous webhook queues for enterprise post-purchase email suites (POST a tracking number to register a tracker, store a tracker ID in your database, and wait for an async webhook to fire).
lastscanned is built for synchronous, stateless GET lookups and AI agent tool calls (MCP + HTTP 402 Stripe MPP) with predictable unique-number pricing.
Capability / Metric
lastscanned
AfterShip
EasyPost
Ship24
17TRACK
Primary request model
Synchronous GET /v1/track/{number} (live JSON in one HTTP call; zero registration)
Async POST tracker registration + webhook queue
POST tracker creation tied to carrier/label accounts
Async POST tracker webhook (sync per-call locked to $99/mo tier)
Async POST register number first + webhook / subsequent poll
Database / webhook state required
None (stateless)
Must store tracker IDs & run webhook endpoints
Must store trk_... IDs & webhook handlers
Must register trackers (on standard plan)
Must register numbers against prepaid quota
Entry API tier
$0/mo Free (5 numbers/day + 1 keyless lookup/day per IP)
$59/mo Premium (API access excluded on Essentials)
Pay-as-you-go ($0.01–$0.03/tracker) or $20/mo BYOCA
$0 Free (10/mo), then $39/mo (per-shipment) or $99/mo (per-call)
200 one-time free, then $119/yr prepaid (5,000/yr)
Cost for 1,000 unique packages / month
$4.99 / month (Pro)
$59.00 / month (Premium)
$20.00 / month ($0.02/tracker)
$39.00 / month (or $99/mo per-call)
$19.83 / month eq. ($119/yr annual lock-in)
Overage rate above 1,000 packages
$0.015 per extra unique tracking number
$0.08 per shipment
$0.01–$0.03 per tracker
$0.039–$0.045 per shipment
Prepaid annual tier upgrade required
Cost of re-polling the same package 20x in a month
$0 (unlimited re-polls included on Pro)
Included after async registration
Included on registered tracker
Included on per-shipment tier; 20x charges on per-call tier
Included after registration
Failed / carrier-error lookup billing
Always $0 (only 200 or 404 count)
Quota consumed on registration
Charged on tracker creation
Quota consumed on tracker creation
Quota consumed on registration
Carrier credentials required
Zero across all 31 carriers
Zero (for standard public carriers)
Often requires BYO carrier credentials for full data
Zero
Zero
US, CA & AU regional couriers (uniuni, speedx, gofo, veho, intelcom, bettertrucks, cdl, axlehire, sendle)
All 13 built-in
Partial (enterprise post-purchase focus)
Thin on China/Temu/Shein US regional last-mile
Partial aggregator coverage
Strong on China export, mixed on US regional
92…"USPS Currently Awaiting Package" middle-mile consolidator scans
Built-in via ?carrier=osm & ?carrier=pitneybowes
Requires separate courier slug / tracker registration
Returns USPS pre-shipment status until USPS scan
Depends on courier auto-detection
Depends on courier auto-detection
Cross-border last-mile handoff number extraction
Top-level message ("Handed to <carrier> as <number>") across all 8 cross-border carriers
In interactive workflows—such as "Where Is My Order?" (WISMO) AI support agents, live chat widgets, helpdesk macros, and on-demand order-lookup pages—a customer asks about a package right now.
With legacy webhook platforms (AfterShip, 17TRACK, Ship24's standard plan), looking up an unregistered tracking number requires a multi-step dance:
POST the tracking number to create a tracker in their database.
Receive an initial PENDING status with an empty events: [] array while their background queue schedules a job.
Wait seconds or minutes for an inbound webhook before your application can answer the customer's question.
With lastscanned, there is no tracker registration step and no webhook receiver to host. Call GET https://api.lastscanned.com/v1/track/{trackingNumber} (or pass up to 100 numbers to GET /v1/track?numbers=...) and receive the live normalized status and full scan timeline in the same HTTP response.
Tracking APIs typically force an unpleasant billing trade-off:
Per-shipment enterprise plans (AfterShip at $59/mo, Ship24 at $39/mo) charge steep monthly minimums bundled with branded tracking pages, email marketing flows, and returns portals you may not need.
Per-call APIs charge every single time you poll a tracking number—so polling an active shipment 15 times over 5 days costs 15 API credits.
lastscanned combines synchronous GET simplicity with unique-number monthly billing:
Free tier ($0/mo): 5 unique tracking numbers per day (plus 1 unauthenticated keyless lookup per day per IP so anyone can test GET /v1/track/:number immediately).
Pro tier ($4.99/mo): Includes 1,000 unique tracking numbers per monthly billing period, then $0.015 per additional unique tracking number.
Unlimited re-polls: Once your account looks up a tracking number during a billing period, every subsequent GET /v1/track/:number or MCP track_package call for that same tracking number is free for the rest of the billing period.
Failure protection: Only lookups where the carrier returns a tracking result (200) or confirms 404 not_found count toward your daily allowance, Pro unique-number count, or MPP credit pack. Upstream timeouts or 502 carrier_error responses never cost a cent.
lastscanned is designed from the ground up for both human developers and autonomous AI agents:
Zero-install remote MCP server (https://mcp.lastscanned.com): Connect Claude Code, Cursor, Windsurf, or custom agents over Streamable HTTP in one command—no local wrapper scripts required:
For MCP clients that cannot send custom HTTP headers (such as ChatGPT Developer Mode connectors), pass the API key directly in the URL path: https://mcp.lastscanned.com/lsk_live_YOUR_API_KEY.
Keyless pay-per-request via Stripe Machine Payments Protocol (HTTP 402): When an autonomous agent calls GET /v1/track/{trackingNumber} without an API key after using the IP's 1 free daily lookup (or calls the batch endpoint), lastscanned returns an HTTP 402 Payment Required response with a standard WWW-Authenticate: Payment challenge (mpp.dev, discovery spec at https://api.lastscanned.com/openapi.json):
Card rail (stripe/charge): Pay $0.50 via a Stripe Shared Payment Token for a 25-tracking-number credit pack. Unused credits are returned in the x-lastscanned-key response header (lsk_pack_<32hex>) and credits.key JSON field so the agent can reuse them as a standard Bearer lsk_pack_... token on future requests or MCP calls.
Stablecoin rail (tempo/charge): Pay $0.02 per tracking number in USDC on Tempo.
Two of the largest sources of "Where Is My Order?" support tickets happen in the handoff gap between carriers:
Domestic 92… USPS consolidator parcels (OSM Worldwide & Pitney Bowes):
Millions of US e-commerce parcels ship via OSM Worldwide or Pitney Bowes bearing a 22-digit 92… (or 30-digit 420 + ZIP + 92…) USPS IMpb barcode. While the consolidator moves the parcel across its regional hubs for 3–7 days, querying USPS only returns "Pre-Shipment: Picked Up by Shipping Partner, USPS Awaiting Item" ("USPS Currently Awaiting Package"). With lastscanned, passing ?carrier=osm or ?carrier=pitneybowes on that exact same 92… number queries the consolidator directly and returns every intermediate hub arrival/departure scan plus the consolidator's estimatedDelivery date.
Cross-border last-mile handoff extraction (Yanwen, 4PX, Cainiao, YunExpress, CNE Express, SunYou, UBI Smart Parcel, Asendia):
When an international parcel clears customs and is handed to a local courier (USPS, UniUni, SpeedX, GOFO, OnTrac, Canada Post, Intelcom / Dragonfly, Australia Post, or Royal Mail), lastscanned extracts both the destination carrier and the secondary tracking number into the top-level message field (for example, "Handed to UniUni as UUS5BM1269395824723"), allowing your app or AI agent to chain a second lookup on the local doorstep barcode automatically.