DOCS

Batch dispatch (consolidation)

Batch dispatch (consolidation)

Bundle a day's Japan Post parcels into one deferred-payment dispatch slip with the consolidation flow.

This document walks through the three-stage flow for creating a Japan Post deferred-payment dispatch batch via the Zonos GraphQL API: open a consolidation, attach n shipments to it, then close it to receive Japan Post's dispatch slip (manifest document).

When to use this flow 

Japan Post's deferred-payment program (後納) lets a merchant settle their daily shipping bill in one transaction at end-of-day, rather than per-parcel at drop-off. The merchant brings all the day's parcels to the post office along with one dispatch slip (差出票) covering up to 250 shipments. Postage is invoiced to the merchant's pre-registered Later Pay Number.

If you're shipping individual Japan Post labels and paying parcel-by-parcel at the counter, you don't need this flow — call the single-shipment chain directly without a consolidation.

Overview 

1. shipmentConsolidationCreate            → open the batch (returns consolidation ID)
2. Attach shipments × n                   → create each shipment + label, attached to the batch
3. shipmentConsolidationUpdate(CLOSED)    → close the batch (returns the dispatch slip)

There are two ways to attach shipments to the batch — use whichever fits your integration (or mix them):

  • Attach at label-creation time — thread the consolidation ID from step 1 into each shipmentCreateWorkflow call via the shipmentConsolidationId field.
  • Attach existing shipments by ID — pass shipmentIds on shipmentConsolidationCreate (to seed the batch) or on shipmentConsolidationUpdate (to add to an open batch). Each shipment must already have its Japan Post label.

Either way, each label is created with your Later Pay Number embedded so that Japan Post will accept it onto the dispatch slip when step 3 closes the batch.

Why separate calls instead of one mutation? Steps 2.1, 2.2, ..., 2.n happen across the merchant's day — labels are printed and parcels are sealed as orders come in. The batch can't be a single round-trip the way the single-shipment chain is: there's a multi-hour gap between opening the consolidation and closing it.

Prerequisites 

Before this flow works for a given Verified Account:

  • Your account must have a Japan Post deferred-payment Later Pay Number (後納お客様番号) saved on it — a hyphen-formatted value like 1111111111-222222-3333333333-444444. Pass it on shipmentConsolidationCreate via accountNumber (Step 1).
  • Your API key must hold SHIPMENT_WRITE, plus the standard scopes the per-shipment workflow needs.

Endpoint and authentication 

All three steps below are GraphQL operations sent to the same endpoint. What you pass in the headers depends on your setup — pick your tab.

URL:

https://api.zonos.com/graphql

Headers:

You ship your own orders under your own Verified Account. Authenticate as yourself — no account key needed.

credentialToken: {{YOUR_API_TOKEN}}

Where to find it: Zonos Dashboard → SettingsIntegrations → the Account Key section. Copy the token on the API key row; that is your credentialToken.

Example request 

A copy-and-adapt example of opening a consolidation — the mutation, its variables, and the response. This is the batch-specific call that starts the flow; attaching shipments (Step 2) reuses the single-shipment example, and closing the batch (Step 3) returns the manifest document. Each field is broken down in the steps below.

1mutation ShipmentConsolidationCreate(
2$input: ShipmentConsolidationCreateInput!
3) {
4 shipmentConsolidationCreate(input: $input) {
5 id
6 status
7 accountNumber
8 carrierCode
9 }
10}

Step 1: shipmentConsolidationCreate 

Opens the consolidation. The carrier code locks the batch to Japan Post; all member shipments must use Japan Post service levels. If you already have labeled shipments ready, seed the batch with their IDs via shipmentIds — otherwise create it empty and attach shipments in step 2.

Mutation:

mutation {
  shipmentConsolidationCreate(
    input: {
      carrierCode: JAPAN_POST
      accountNumber: "1111111111-222222-3333333333-444444"
      name: "Tokyo dispatch — 2026-05-01"
      externalId: "merchant-batch-20260501-001"
      shipmentIds: ["shipment_01hxa...", "shipment_01hxb..."]
    }
  ) {
    id
    status
    accountNumber
    carrierCode
    shipments {
      id
    }
  }
}
FieldNotes
carrierCodeRequired. Use JAPAN_POST.
accountNumberHyphen-formatted Later Pay Number. Format is validated at create time — bad values are rejected immediately rather than at close. If omitted, the default account number saved on your Japan Post account is used.
nameOptional. Human-readable label for your records. Defaults to the consolidation's generated ID.
externalIdOptional. Your internal batch identifier; defaults to the consolidation's generated ID if omitted.
shipmentIdsOptional. IDs of initial shipments to attach. Leave empty to open the batch first and attach shipments as their labels are created in step 2.
shipmentIdDeprecated — use shipmentIds instead.

Response:

{
  "data": {
    "shipmentConsolidationCreate": {
      "id": "shco_01hjk...",
      "status": "OPEN",
      "accountNumber": "1111111111-222222-3333333333-444444",
      "carrierCode": "JAPAN_POST",
      "shipments": [
        { "id": "shipment_01hxa..." },
        { "id": "shipment_01hxb..." }
      ]
    }
  }
}

Hold on to the id (e.g. shco_01HJK...) — you'll use it for everything below. The status is OPEN until step 3.

Step 2: Attach shipments 

For each parcel you need to ship today, run the full chained single-shipment workflow to create the shipment and its label. Then attach the shipment to the batch using either of the methods below.

Option A: Attach at label-creation time

Pass the consolidation ID on the final shipmentCreateWorkflow step of the chain. All preceding mutations in the chain are identical to the single-shipment workflow.

The relevant fields on shipmentCreateWorkflow:

shipmentCreateWorkflow(
  input: {
    serviceLevel: "japan_post.air.ems_merchandise"
    shipmentConsolidationId: "shco_01hjk..."
    generateLabel: true
  }
) {
  id
  trackingDetails {
    number
  }
  shipmentCartons {
    label {
      labelImage
    }
  }
}
FieldNotes
shipmentConsolidationIdThe ID from Step 1. Tells the platform "attach this shipment to that batch." This is the only field that distinguishes a consolidation-bound shipment from a standalone one.
serviceLevelMust be a Japan Post service level (japan_post.*). Mixing carriers within a single consolidation is not supported.

Option B: Attach existing shipments by ID

If your shipments are already created and labeled, add them to the open batch with shipmentIds on shipmentConsolidationUpdate:

mutation {
  shipmentConsolidationUpdate(
    input: {
      id: "shco_01hjk..."
      shipmentIds: ["shipment_01hxd...", "shipment_01hxe..."]
    }
  ) {
    id
    status
    shipments {
      id
    }
  }
}

Leave status out of the input while you're still adding shipments — the batch stays OPEN. Each shipment must use a Japan Post service level and have its label (tracking number) before the batch is closed in Step 3.

What attachment means for the label

Whichever option you use, when a Japan Post shipment is part of a consolidation:

  • The shipment has a tracking number, as usual.
  • The shipping-label PDF does not include the customer/post-office receipt copies. Those receipts are deferred to Step 3, where they're bundled into the dispatch-slip document for the whole batch.
  • The shipment is associated with the consolidation; you can re-query it via shipmentConsolidation(id: ...) to see its members.

Repeat this step for every parcel in the day's batch. Up to 250 shipments per consolidation; attempting to close a larger batch fails with a clear validation error before any Japan Post call is made.

You can also verify the batch's contents before closing:

query {
  shipmentConsolidation(id: "shco_01hjk...") {
    status
    shipments {
      id
      trackingDetails {
        number
      }
    }
  }
}

Every shipment should show a tracking number here. If one doesn't, its label was never created — sort that out before closing. status is OPEN until the consolidation is closed in Step 3.

Step 3: shipmentConsolidationUpdate(status: CLOSED) 

Closes the batch. This is the call that asks Japan Post to generate the deferred-payment dispatch slip covering every member's tracking number, and attaches the resulting PDF to the consolidation.

Mutation:

mutation {
  shipmentConsolidationUpdate(input: { id: "shco_01hjk...", status: CLOSED }) {
    id
    status
    statusTransitions {
      status
      changedAt
      note
    }
    customsDocuments {
      documentType
      fileUrl
    }
  }
}
FieldNotes
idThe consolidation ID from Step 1.
statusSet to CLOSED to close the batch and produce the dispatch slip.
shipmentIdsOptional. Adding shipments + closing in the same call is supported — the shipments are attached first, then the batch is closed.

On a CLOSED request:

  1. The consolidation is validated: ≤250 shipments, and every member must have a tracking number. If a shipment is missing its tracking number (its label was never created), the call is rejected.
  2. Japan Post is asked to generate a deferred-payment dispatch slip covering every member's tracking number.
  3. The status briefly moves to MANIFEST_CREATED while the slip PDF is being fetched, then to CLOSED once the document has been attached.
  4. The dispatch slip PDF (one file containing the slip plus every member's customer/post-office receipts) is attached to the consolidation as a CustomsDocument with documentType: MANIFEST_DOCUMENT.

Response:

{
  "data": {
    "shipmentConsolidationUpdate": {
      "id": "shco_01hjk...",
      "status": "CLOSED",
      "statusTransitions": [
        {
          "status": "OPEN",
          "changedAt": "2026-05-01T08:00:00Z",
          "note": "Shipment batch created"
        },
        {
          "status": "MANIFEST_CREATED",
          "changedAt": "2026-05-01T17:30:12Z",
          "note": "Dispatch slip created with Japan Post"
        },
        {
          "status": "CLOSED",
          "changedAt": "2026-05-01T17:30:14Z",
          "note": "Dispatch slip downloaded and uploaded"
        }
      ],
      "customsDocuments": [
        {
          "documentType": "MANIFEST_DOCUMENT",
          "fileUrl": "https://customs-docs.zonos.com/.../japanpost-dispatch-slip.pdf"
        }
      ]
    }
  }
}

Retrieving the documents

The dispatch slip is attached directly to the consolidation as a CustomsDocument with documentType: MANIFEST_DOCUMENT — grab the fileUrl from the close response above, or query for it any time later:

query {
  shipmentConsolidation(id: "shco_01hjk...") {
    status
    customsDocuments {
      documentType
      fileUrl
    }
  }
}

Print the PDF at fileUrl. It contains:

  • Page 1: The deferred-payment dispatch slip — hand this to the post office.
  • Pages 2+: The customer/post-office receipts for each parcel — one stapled to each parcel, the other kept by the post office.

Once printed, bring the parcels + the dispatch slip + the receipts to the post office in one trip. Japan Post invoices your Later Pay Number at the end of the billing period.

Putting it together 

A representative day for a merchant shipping 50 Japan Post parcels looks like:

08:00 → shipmentConsolidationCreate(JAPAN_POST, accountNumber)  → shco_01HJK...
08:30 → CreateDeclarationShipment( ... shipmentConsolidationId: "shco_01HJK..." )    parcel 1
09:15 → CreateDeclarationShipment( ... shipmentConsolidationId: "shco_01HJK..." )    parcel 2
...
16:45 → CreateDeclarationShipment( ... shipmentConsolidationId: "shco_01HJK..." )    parcel 50
17:30 → shipmentConsolidationUpdate(id: "shco_01HJK...", status: CLOSED)
17:32 → Print PDF

Prefer to batch at the end of the day instead? Create the day's labels without a consolidation ID, then open the consolidation once with every shipmentIds value (or add them in chunks via shipmentConsolidationUpdate) and close it in the same or a follow-up call.

If you ship across multiple business units / billing accounts, run a separate consolidation per account — pass a different accountNumber on each shipmentConsolidationCreate and route shipments accordingly. Shipping more than 250 parcels in a day? Open a second consolidation.

Error handling 

Validation errors (caught before any Japan Post call)

  • accountNumber malformed — rejected at Step 1 (shipmentConsolidationCreate) before the consolidation is even saved. Error message identifies the offending segment.
  • >250 shipments — rejected at Step 3, before the Japan Post call is made.
  • Member shipment missing a tracking number — rejected at Step 3. Means a label create silently failed earlier; investigate the affected shipment via shipment(id: ...) { trackingDetails }.
  • No deferred-payment number set on the consolidation — rejected at Step 3. Pass accountNumber on shipmentConsolidationCreate, or save a default account number on your Japan Post carrier account.

Japan Post API errors

If Japan Post rejects the dispatch slip request, the close mutation surfaces the carrier's error code and message as a GraphQL error. The most common:

CodeMeaningWhat to check
E034Deferred customer numbers missingaccountNumber on the consolidation.
E035Tracking numbers must be 13 chars separated by -Member shipments somehow have malformed tracking numbers.
E036Tracking numbers must be alphanumericSame as above.
E037Not a valid deferred shipmentA member's label was created without the deferred-payment customer number. Contact Zonos support.
E046Total weight requiredUpstream label create was malformed. Contact Zonos support.
50Parameter format errorField-length or type violation on the input.
51Authentication errorContact Zonos support.

Retries

If the close call fails after Japan Post has accepted the dispatch slip request (i.e. during PDF retrieval), retrying shipmentConsolidationUpdate(status: CLOSED) is safe — the platform will skip the carrier call and just re-attempt fetching and attaching the document.

If the close fails before Japan Post has accepted the request (validation error, E0xx, network timeout), no state has changed — fix the root cause and retry.

GraphQL API ReferenceTypes, inputs, and operations used in this guide
Book a demo

Was this page helpful?