Developer guides

CSV shipment import API: async jobs and per-row results

For warehouse exports, seller uploads and backfills that need recoverable processing instead of a long synchronous request.

By Trace · Reviewed

A durable shipment import accepts a file-shaped request, creates an owned job and records the outcome of each row. Your application can inspect progress and continue after a restart without treating one successful HTTP response as proof that every parcel was tracked.

Trace imports create shipment records. They do not perform a synchronous bulk carrier lookup or guarantee a verified timeline for every row. Distinguish uploaded rows, created records and usable source observations throughout the workflow.

Choose imports for records and batches for immediate lookups

POST /v1/imports accepts JSON rows or CSV text and returns HTTP 202 with an owned job ID. Use it to populate order-linked records and then inspect processing results. POST /v1/track/batch is a different operation: up to 20 synchronous lookups with a per-item result envelope.

For a seller upload containing 600 parcels, the durable import gives operators progress and row-specific errors. For a support agent checking two authorized parcel numbers, a small lookup batch may be appropriate. Neither operation should block a buyer-facing page while a large amount of carrier work completes.

OperationWhat success meansBest fit
POST /v1/importsA job was accepted; row processing creates recordsSeller uploads, warehouse CSV exports, record backfills.
POST /v1/track/batchPer-item carrier lookup results are availableSmall lookup groups requiring an immediate response.
GET /v1/shipments/:idAn owned record was readReconcile identity, verification time and monitoring state.

Validate the CSV contract before sending it

Supported CSV columns are tracking_number, carrier, order_id, reference and destination_country. Quoted commas and newlines are supported. The request accepts up to 1,000 rows, or CSV text up to 750 KB. It is the CSV content inside JSON, not a multipart file-upload endpoint.

Use actual carrier numbers and a catalog carrier override when known. Country codes must use two uppercase letters. Do not add unsupported columns and assume they will become record fields. Keep private buyer data out of a tracking import unless it is necessary and supported by your own record policy.

CSV shape · illustrative rows, replace with authorized real numbers

tracking_number,carrier,order_id,reference,destination_country
REPLACE-WITH-REAL-NUMBER,ups,order-1042,"Order #1042, parcel one",US
REPLACE-WITH-ANOTHER-NUMBER,dhl,order-1043,Order #1043,GB

Create an idempotent job and save its ID

Use one stable Idempotency-Key for a particular import attempt and its exact input. Reusing a key with changed input is a conflict, not a way to append new rows. Save the job ID in your application before moving on so the operator can resume inspection after a restart.

The official SDK is distributed as a versioned hosted package. Install the documented download and keep it on the server; do not assume an npm or PyPI registry publication. This example reads a local CSV file and creates records, so running it changes your account state.

Node.js SDK · server-side record import

import { readFile } from 'node:fs/promises';
import { Trace } from '@traceapi/sdk';
const file = process.env.CSV_FILE;
if (!file) throw new Error('Set CSV_FILE to an authorized import');
const csv = await readFile(file, 'utf8');
if (Buffer.byteLength(csv, 'utf8') > 750000) throw new Error('CSV too large');
const apiKey = process.env.TRACE_API_KEY;
if (!apiKey) throw new Error('Set TRACE_API_KEY');
const trace = new Trace(apiKey);
const { job } = await trace.createImport({ csv }, 'warehouse-export-1042-v1');
console.log('Save this job ID:', job.id);
const { job: progress } = await trace.importJob(job.id);
console.log(progress.status);
// Poll at a bounded interval and inspect results as processing progresses.

Reconcile each row, including rejected rows

Read GET /v1/imports/:id/results with after_row and limit. The response contains data and next_row for continuation. A created row includes its record identity; a rejected row preserves the row’s error. Associate these outcomes with the seller or warehouse row references in your own system.

If you only count accepted HTTP requests, a file with invalid carrier codes can look successful. Report submitted rows, created records and row errors separately. A record without last_checked_at or verified tracking data remains different from a parcel with usable events.

For example, an operator can correct three failed rows from a 600-row file without blindly resubmitting every successful parcel. Build that correction workflow deliberately with new, consistent input identities rather than assuming the import key can be edited in place.

Plan cancellation, concurrency and verification

An account can have at most two unfinished imports. Processing uses bounded chunks and recoverable leases; completed rows remain idempotent across restarts. Cancellation stops remaining rows and preserves completed records, so show the partial outcome rather than promising a rollback of the entire import.

The account’s active-record cap and 20,000 stored-record cap still apply. Monitoring is best effort and successful refreshes share the lookup quota. Record creation itself does not prove a carrier result; inspect each record’s last_checked_at, last_error and monitoring state after acquisition runs.

  • Keep the input file and its row mapping available for reconciliation under your own retention policy.
  • Use a sandbox UI state for no-scan and exception presentation before importing live records.
  • Bound polling and respect API admission limits instead of retrying job reads in a tight loop.
  • Test cancellation after partial completion and a restarted consumer reading the saved job ID.
  • Count verified carrier timelines separately from the import’s created-record count.

Common questions

Does import completion mean all parcels were tracked successfully?

No. It means processing reached its recorded outcome. Successful rows create records; verified tracking is a separate acquisition result.

Can cancellation undo already created records?

No. Cancellation stops remaining rows and preserves completed records and their outcomes.

Is this a multipart CSV upload route?

No. Send JSON with csv text, or a rows array, using the documented limits and an Idempotency-Key.

References & next steps

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