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
shipmentCreateWorkflowcall via theshipmentConsolidationIdfield. - Attach existing shipments by ID — pass
shipmentIdsonshipmentConsolidationCreate(to seed the batch) or onshipmentConsolidationUpdate(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 onshipmentConsolidationCreateviaaccountNumber(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 → Settings → Integrations → 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.
mutation ShipmentConsolidationCreate($input: ShipmentConsolidationCreateInput!) { shipmentConsolidationCreate(input: $input) { id status accountNumber carrierCode }}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
}
}
}
| Field↕ | Notes↕ |
|---|---|
carrierCode | Required. Use JAPAN_POST. |
accountNumber | Hyphen-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. |
name | Optional. Human-readable label for your records. Defaults to the consolidation's generated ID. |
externalId | Optional. Your internal batch identifier; defaults to the consolidation's generated ID if omitted. |
shipmentIds | Optional. IDs of initial shipments to attach. Leave empty to open the batch first and attach shipments as their labels are created in step 2. |
shipmentId | Deprecated — 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
}
}
}
| Field↕ | Notes↕ |
|---|---|
shipmentConsolidationId | The 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. |
serviceLevel | Must 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
}
}
}
| Field↕ | Notes↕ |
|---|---|
id | The consolidation ID from Step 1. |
status | Set to CLOSED to close the batch and produce the dispatch slip. |
shipmentIds | Optional. Adding shipments + closing in the same call is supported — the shipments are attached first, then the batch is closed. |
On a CLOSED request:
- 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.
- Japan Post is asked to generate a deferred-payment dispatch slip covering every member's tracking number.
- The status briefly moves to
MANIFEST_CREATEDwhile the slip PDF is being fetched, then toCLOSEDonce the document has been attached. - The dispatch slip PDF (one file containing the slip plus every member's customer/post-office receipts) is attached to the consolidation as a
CustomsDocumentwithdocumentType: 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)
accountNumbermalformed — 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
accountNumberonshipmentConsolidationCreate, 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:
| Code↕ | Meaning↕ | What to check↕ |
|---|---|---|
E034 | Deferred customer numbers missing | accountNumber on the consolidation. |
E035 | Tracking numbers must be 13 chars separated by - | Member shipments somehow have malformed tracking numbers. |
E036 | Tracking numbers must be alphanumeric | Same as above. |
E037 | Not a valid deferred shipment | A member's label was created without the deferred-payment customer number. Contact Zonos support. |
E046 | Total weight required | Upstream label create was malformed. Contact Zonos support. |
50 | Parameter format error | Field-length or type violation on the input. |
51 | Authentication error | Contact 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.
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
nshipments to it, then close it to receive Japan Post's dispatch slip (manifest document).