Shipping APIs 7 min read

FedEx Open Ship: The Consolidation API Hiding in the Ship API

Consolidating export parcels under one master shipment is often run by hand through a desktop tool, on the assumption that the shipping API can't do it. It can — FedEx's Ship API exposes it as Open Ship. Here's what Open Ship is, the request shape that actually works, and the four things about it the docs gloss over.

Updated Aug 2026
FedEx Open Ship: The Consolidation API Hiding in the Ship API

The Consolidation Step That Gets Run by Hand #

You have a batch of export parcels going to different buyers, and they need to move as one consolidated shipment under a single master air waybill — one customs clearance, many child labels. The received wisdom for doing this on some carrier lanes is a manual one: fill a spreadsheet, run a desktop tool on a Windows PC, and re-import the PDFs it spits back. The programmatic shipping API, the story goes, does single labels but not consolidation.

On FedEx, that story is wrong. The consolidation lives in the same Ship API you already call for single labels, under a capability called Open Ship. There is no separate product to license and no hidden host — it's part of the documented FedEx Ship API on the same apis.fedex.com you use for everything else.

This post is about what Open Ship actually is, the request loop that works in practice, and the handful of behaviours that will cost you an afternoon if you don't know them first.

Parcels being consolidated for shipping
Consolidation was reachable through the documented API all along.

What Open Ship Is #

Open Ship is FedEx's pattern for building one shipment incrementally, across multiple calls, and tying the pieces together under a single master tracking number. Instead of one request that produces one label, you open a shipment, add each parcel to it as a package, and the master tracking number that comes back represents the whole consolidation. The individual parcels come back as child tracking numbers underneath it.

That master-and-children structure is the consolidation the manual tool was producing. The desktop utility that sits in many of these workflows is a convenience wrapper around this API — nothing more. Once you call Open Ship directly, the manual step comes out of the loop.

Mental model: a single label call is fire-and-forget. Open Ship is a small build: create, add packages, and read back the one master waybill that binds them. If you already build a normal requestedShipment body, you already have most of the payload.

The Flow That Actually Works #

The endpoint is POST /ship/v1/openshipments/create, authenticated with the same OAuth token as the rest of the Ship API. Each call carries three things that matter: an index (the key that identifies the parcel within the open shipment), an openShipmentAction such as CREATE_PACKAGE, and your usual requestedShipment block with the recipient, customs and commodity detail. It's the same requestedShipment shape as a normal label call — see the Ship API reference — which is why an existing single-label integration ports over cleanly.

Looping create calls with a unique index per parcel builds one consolidation: the first call returns the master tracking number, and each parcel returns a child tracking number under it create · index 1 CREATE_PACKAGE create · index 2 CREATE_PACKAGE create · index N unique index each Master tracking # from the first response child label 1 child label 2 child label N One master waybill, one customs clearance, many child labels — built with N create calls.

The working shape, validated live against the FedEx sandbox as of August 2026, is a loop: one create per parcel, and you read the master tracking number off the first response — there is no separate fetch for it.

POST /ship/v1/openshipments/create
{
  "index": "PARCEL-1",              // unique per call
  "openShipmentAction": "CREATE_PACKAGE",
  "accountNumber": { "value": os.environ["FEDEX_ACCOUNT"] },
  "requestedShipment": { /* recipient, customs, commodities … */ }
}

// response
"transactionShipments": [
  { "masterTrackingNumber": "…",    // the consolidation, on the FIRST call
    "pieceResponses": [ { "trackingNumber": "…" } ] }
]

Four Things the Docs Gloss Over #

1. The index must be unique per call. Reuse an index value across two parcels and you get SHIPMENT.INDEX.INUSE back. Generate a fresh index for every child — a running counter or the order reference works — and never re-send one within the same batch.

2. In practice you loop create; a separate confirm step 404s. Open Ship is described as a lifecycle — create, add, confirm. Against the REST endpoint as of August 2026, the consolidation formed cleanly from repeated create calls with CREATE_PACKAGE, while a /modify or /confirm path returned 404. Build for the loop; don't wait on a confirm call that isn't there.

3. A consolidation needs at least two parcels. One parcel is a single shipment, not a consolidation — the API enforces a minimum of two. Guard for it before you submit a batch of one, or you'll surface a carrier error to the operator for something you could have caught.

4. The sandbox validates the shape but won't hand you labels for a gated program. The sandbox returns HTTP 200 and real-looking master and child tracking numbers, which is enough to prove your request body is correct. But for an export-clearance consolidation, a sandbox account that isn't enrolled in that program returns a warning and empty packageDocuments — no label PDF. The actual labels only materialise on a production account entitled for the program.

The sandbox can look like success and produce nothing shippable. HTTP 200 with tracking numbers but empty packageDocuments is not a bug — it's a gated program on an unentitled account. Confirm the entitlement on the production key before you conclude the integration is done, and make your first production run a small, voidable one.

What We Built On Top of It #

The integration is one adapter that composes the existing transport and ship-request builder — the same code that already produces the recipient block, the customs commodities, the export identifiers and the paperless-trade upload — and wraps it as an Open Ship CREATE_PACKAGE body. It returns the same consolidation result the rest of the system already consumes, so nothing downstream changed: the master waybill, the merged mother invoice, the per-child invoices and the label bundle all just work.

Two decisions kept it safe to ship next to the manual path rather than instead of it:

  • It's behind a feature flag, off by default. Turning it on is a deliberate configuration act, exactly like the dry-run pattern you want on any API that produces real, billable shipments.
  • It falls back. If the flag is off, or the account key isn't entitled, or the endpoint can't run for any reason, the batch drops to the per-parcel label path and still produces labels. A new consolidation route should never be able to leave a batch with no labels at all.

The manual desktop step still exists for anyone who wants it. It's just no longer the only way to get a consolidated export shipment — the same outcome now comes from one call the operator never sees.

The Habit This Teaches #

The lesson generalises past FedEx. When a workflow routes something through a manual tool "because the API doesn't do it," the cheapest thing you can do is read the vendor's full documented API surface before you accept that. Convenience wrappers exist precisely because an API is powerful but fiddly — which means the capability is usually right there in the catalog, one endpoint over from the one you already use.

Logistics APIs reward this more than most, because they are older and broader than their marketing suggests. The consolidation was documented the whole time, sitting in the FedEx API catalog next to the endpoints everyone already uses; it just wasn't the one anyone reached for first.

Building marketplace-to-carrier shipping from India? The other carrier lane has its own surprises — see the DHL India CSB-V API that returns a delimited string — and missing recipient data is a whole separate problem, covered in why no marketplace gives you a buyer phone number. If you're wiring a multi-account seller operation to FedEx and DHL, talk to me about the pipeline.

FAQ #

Does the FedEx Ship API support shipment consolidation?

Yes. The ship/v1/openshipments surface (Open Ship) builds one shipment incrementally across multiple calls and returns a single master tracking number that ties the child parcels together. It is the same Ship API and host as single-label shipping, not a separate product.

What is a master tracking number in Open Ship?

It is the identifier for the whole consolidation, returned on the first create response. Each parcel added to the open shipment comes back with its own child tracking number underneath that master, which is what makes it one customs clearance across many labels.

Why do I get SHIPMENT.INDEX.INUSE?

Because you reused an index value across two create calls in the same open shipment. The index must be unique per parcel; generate a fresh one for every child.

Why does the sandbox return tracking numbers but no label?

An HTTP 200 with a master and child tracking number confirms your request body is valid, but for a gated export-clearance consolidation an unentitled sandbox account returns a warning and empty packageDocuments. The label PDFs only appear on a production account enrolled in that program.

Do I need a separate confirm call to complete an Open Ship consolidation?

In testing against the REST endpoint as of August 2026, no — the consolidation formed from repeated create calls with CREATE_PACKAGE, and a separate confirm path returned 404. Build the loop and read the master tracking number off the first response.

Don't want to build this yourself?

I set this up for sellers and agencies every week. Book a free 30-minute audit of your Amazon data & PPC setup — you'll leave with a plan either way, whether we work together or not.

Found this helpful? Share it:

WhatsApp