Developer guides

Asynchronous shipment tracking jobs for slow carrier lookups

For backends that need lookup results without holding a single HTTP connection open.

By Trace · Reviewed

An asynchronous tracking job separates submission from acquisition. The submission acknowledges queued work; it does not certify that all parcels have been tracked. Your application stores the returned job ID and reads progress and individual outcomes later.

Trace accepts 1–20 tracking numbers per job with a required Idempotency-Key. These jobs perform lookups without creating monitored shipment records. A CSV import instead creates shipment records, so choose the operation that matches the business task.

Persist the job identity before polling

Use a stable key for one intended job submission and preserve the exact request body on retries. HTTP 202 returns an owned job and a Location header. A changed body with the same idempotency key is a conflict, not a way to edit a running job.

TypeScript SDK 0.3.0 · server-side submission and reads

const { job } = await trace.createTrackingJob({
  tracking_numbers: ["YOUR_NUMBER", "ANOTHER_NUMBER"],
  carrier: "ups",
  allow_stale: false,
}, "your-stable-batch-key");
const progress = await trace.trackingJob(job.id);
const page = await trace.trackingJobResults(job.id, { after_row: 0 });
// Save job.id in your application; inspect every row in page.

Do not mistake pagination for a completion stream

Rows may be queued, processing, succeeded, failed or cancelled. Results pagination is ordered by row, not by the time a row finishes. While a job is running, re-read pending rows from the start instead of advancing a cursor once and assuming earlier rows can never change.

A completed job can contain failed items. Show the outcome counts and preserve the successful subset. The user should be able to distinguish “work finished” from “all lookups succeeded.”

Plan for concurrency, expiry and quota

There can be at most two unfinished jobs and 1,000 retained jobs per account. Each job expires after 60 minutes. Quota is reserved when an item is claimed, so a successful submission does not reserve enough quota for every eventual result.

Persisted successful results consume one monthly lookup each, including cached and explicitly requested stale results. Failed items and cancelled uncommitted work release reservations. Keep the UI responsive to quota failures instead of polling forever for an outcome that cannot succeed in the current period.

Cancel deliberately and preserve completed work

Cancellation stops remaining work and fences late completion, but a source request that already started may still finish. Completed results are retained. Do not tell a customer that cancellation erased earlier successful lookups or undid quota already consumed.

Terminal results and idempotency are retained for at least seven days, then become eligible for cleanup. A key whose retained record has been removed can create new work. Store any results needed for your own retention period in your application and make later retries deliberate.

Common questions

Should I use an async job or a CSV import?

Use a job to retrieve tracking results. Use an import to create owned shipment records for ongoing monitoring; import success itself is not a live carrier result.

References & next steps

Implementation details were checked against Trace’s current API. External product details may change; verify the linked documentation before deciding.