The CreateDeclarationShipment GraphQL workflow takes a Japan Post shipment from raw inputs to a printable label in one round trip.
CreateDeclarationShipment chains together six *Workflow mutations into a single GraphQL request. Each step builds on the data the previous steps provided, and all of them are submitted together so a complete shipment can be created in one round trip:
partyCreateWorkflow → describe origin + destination parties
itemCreateWorkflow → describe the line items
cartonsCreateWorkflow → describe the physical packaging
shipmentRatingCreateWorkflow → record the carrier rate quote
landedCostCalculateWorkflow → calculate duties / taxes / fees
shipmentCreateWorkflow → create the shipment + label
The Workflow mutations are designed to be chained: you don't need to thread IDs from one step into the next, and you don't need to send a separate request per step. Submit the whole document, get the final Shipment back.
When the serviceLevel on the final step is a Japan Post service level (japan_post.*), Zonos calls the Japan Post Label API (code 52) on your behalf using your Verified Account's Later Pay Numbers, generates the label and tracking number, creates the Declaration ID, and links them — all inside that final shipmentCreateWorkflow step.
Why one mutation? Each step depends on the previous one (landed cost needs the items + parties; the label needs everything). Bundling them into a single GraphQL document keeps the data consistent and avoids five extra round trips.
The requests in this chain all use 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.
A complete CreateDeclarationShipment request you can copy and adapt — the mutation, its variables, and the response — for a single Japan Post parcel shipped DDP to the U.S. Each input is broken down in the step-by-step section below.
This is the rate the buyer was quoted at checkout. It feeds into the landed-cost calculation as the "shipping" subtotal so duties and taxes are computed against the correct CIF value.
5. landedCostCalculateWorkflow
Runs the duties, taxes, and fees calculation for the destination country. Uses the items, parties, and shipping cost from the prior steps.
Field↕
Status↕
Notes↕
endUse
Required
NOT_FOR_RESALE or FOR_RESALE. Some destinations apply different rates for commercial vs personal end use.
tariffRate
Required
Defaults to ZONOS_PREFERRED if omitted. Tells Zonos which tariff source/methodology to apply.
calculationMethod
Recommended
DDP (buyer prepays) or DDU (buyer pays at the door). Use DDP for prepaid. Drives whether LandedCost.amountSubtotals includes duty/tax.
currencyCode
Optional
Currency the landed-cost subtotals are returned in.
arrivalDate
Optional
FX rates and tariff schedules are pinned to this date if provided.
The response includes amountSubtotals (duties, taxes, fees, shipping, landedCostTotal) — these are the numbers you display to the buyer at checkout and that get printed on the commercial invoice.
6. shipmentCreateWorkflow
The terminal step — creates the Shipment entity, generates the carrier label, and (optionally) the commercial invoice / packing slip.
For Japan Post Verified Accounts, this is also where Zonos calls the Japan Post Label API (code 52) on your behalf, injects your Later Pay Numbers, creates the Declaration ID, and links the Declaration ID to the tracking number returned by Japan Post.
Key fields:
Field↕
Status↕
Notes↕
serviceLevel
Required for label
The Japan Post service to ship with (e.g. japan_post.air.ems_merchandise). Must be a japan_post.* service level.
generateLabel
Optional
Defaults to true; must be true to return a label.
contentsType
Recommended
Drives customs treatment. One of SALE_OF_GOODS, ECOMMERCE_GOODS, COMMERCIAL_GOODS, COMMERCIAL_SAMPLE, RETURNED_GOODS, GIFT, DOCUMENTS, OTHER.
nonDelivery
Optional
What Japan Post should do if the parcel can't be delivered. See below.
references
Optional
Merchant-supplied reference numbers printed on the label and commercial invoice. See below.
On contentsType, the two most common values for Verified Account traffic are ECOMMERCE_GOODS (sold to a consumer, BtoC) and COMMERCIAL_GOODS (sold between businesses, BtoB). These set the pkgType Zonos sends on the Japan Post label call, so the choice changes what prints on the customs declaration — it isn't just a label.
nonDelivery sub-input
Tells Japan Post what to do with the parcel if it can't be delivered — refused by the consignee, rejected at the border, or undeliverable as addressed.
option accepts exactly these four values. There is no RETURN value — use RETURN_AFTER_RETENTION or RETURN_IMMEDIATELY to pick when the parcel comes back.
option↕
Dashboard equivalent↕
What Japan Post does↕
RETURN_AFTER_RETENTION
Return
Holds the parcel at the destination post for its retention period, then returns it to the sender.
RETURN_IMMEDIATELY
Return
Returns the parcel to the sender right away, with no retention hold.
FORWARD
Redirection
Redirects the parcel to a different address. Additional postage applies.
ABANDON
Renounce
Disposes of the parcel at the destination. Nothing is returned and no return postage is charged.
The API exposes both return variants separately; the Dashboard's Return option covers both.
transportMethod accepts AIR or MOST_ECONOMICAL, and sets how a returned parcel travels back. It only applies to the two RETURN_* options — the Dashboard shows the matching Return method field only when Return is selected.
The If undeliverable picker in the Dashboard Create label dialog writes this same field, so a label created in the Dashboard and a label created through the API behave identically.
references sub-input
These fields print on the carrier label and/or commercial invoice. Use them to surface PO numbers, license numbers, and free-text remarks the consignee or customs authority needs to see.
Field↕
Status↕
Notes↕
Length↕
invoiceNumber
Optional
Merchant invoice number.
—
purchaseOrderNumber
Optional
Merchant PO number.
—
licenseNumber
Optional
Export/import license number.
—
certificateNumber
Optional
Customs certificate number.
—
paymentConditions
Optional
Free-text terms-of-payment shown on the commercial invoice.
Limit to 200 characters — longer values overflow on the printed invoice.
customsRemarks
Optional
Free-text customs remarks.
—
taxCode
Optional
Custom tax code printed on the label.
—
Response
The interesting fields on the returned Shipment are:
{
id
trackingDetails {
number
}
shipmentCartons {
label {
url
labelImage
}}}
trackingDetails.number is the Japan Post tracking number.
The label object can return the label two ways — request whichever fits your workflow (or both):
Field↕
Returns↕
Use when↕
url
A hosted link to the rendered label file (PDF), ready to download or print.
You want to hand off a link — open it, email it, or fetch the file later without holding it in the payload.
labelImage
The base64-encoded label image (PNG/PDF/ZPL) inline in the response.
You want the label bytes directly in the response to attach to a fulfillment workflow or save to your WMS.
Select only the fields you need. Requesting url keeps the response small; requesting labelImage returns the full label inline so you don't need a second round trip to fetch it. The example above requests url.
Service level codes use dots, not underscores. You may see the underscore form (japan_post_air_parcel) in error messages and internal references, but it is not valid input.
Air services
Code↕
Japan Post service↕
Mail type↕
japan_post.air.ems_documents
EMS (documents)
1-0
japan_post.air.ems_merchandise
EMS (merchandise)
1-1
japan_post.air.parcel
International parcel
1-5
japan_post.air.packet
International Air Packet
1-8
japan_post.air.small_packet
Small packet
1-9
japan_post.air.printed_matter_registered
Printed matter, registered
1-A
japan_post.air.printed_matter
Printed matter
1-B
japan_post.air.letter_registered
Letter, registered
1-C
japan_post.air.letter
Letter
1-D
Surface services
Code↕
Japan Post service↕
Mail type↕
japan_post.surface.parcel
International parcel
2-5
japan_post.surface.small_packet
Small packet
2-9
japan_post.surface.printed_matter
Printed matter
2-B
japan_post.surface.letter
Letter
2-D
Choosing between similar services
Small packet vs. International Air Packet. Both are capped at 2 kg. japan_post.air.packet is Japan Post's tracked small-packet service. japan_post.air.small_packet is the untracked equivalent. If you need tracking on a lightweight parcel, use japan_post.air.packet.
Registered variants. For letters and printed matter, tracking is added by the registered (書留) version of the service. japan_post.air.printed_matter and japan_post.air.letter do not include it on their own.
Deprecated codes
japan_post.air.epacket_light was International e-Packet Light. Japan Post renamed the service to International Air Packet on June 1, 2026, and expanded it to all countries and regions. The service itself is unchanged.
The old code still resolves so existing integrations keep working, but use japan_post.air.packet for new work.
Transport-mode codes
japan_post.air, japan_post.surface, japan_post.economy_air, and japan_post.custom also resolve, but they identify a transport mode or a fallback rather than a specific mail product. Use one of the service codes above for normal shipments.
Validate the code you send
An unrecognized serviceLevelCodedoes not raise an error. The request returns HTTP 200 with no errors array, serviceLevel comes back as null, and shipping drops out of the landed cost total — so the response looks correct while the amounts are wrong.
Always assert that shipmentRatingCreateWorkflow.serviceLevel is non-null before relying on the totals.
To pull the current list at any time:
{
serviceLevels(carrier:"carrier_00004c9b-9431-4518-bfbc-b9f8476335b1"){
code
name
}}
This query takes the carrier ID. Passing the carrier code japan_post returns an empty list with no error.
Validation errors (missing required fields, invalid country codes, etc.) come back in the standard GraphQL errors array and abort the rest of the chain.
Japan Post errors (label generation failure, invalid address, etc.) surface as GraphQL errors on shipmentCreateWorkflow. If a retry is needed, contact support — the recommended path is to resubmit the full mutation with corrected input.
VALIDATION_INVALID_TYPE_VARIABLE
{"errors":[{"message":"invalid type for variable: 'shipmentInput'","extensions":{"name":"shipmentInput","code":"VALIDATION_INVALID_TYPE_VARIABLE"}}]}
This error names the whole variable, not the field that's actually wrong. It almost always means one enum value inside that variable isn't a member of its enum — most often nonDelivery.option, contentsType, or serviceLevel.
It is not a JSON-typing problem. Quoting or unquoting your booleans and numbers won't change it, because the payload never gets that far — the enum is rejected first.
To find the bad field, check every enum-valued field in the variable against its accepted values:
Field↕
Accepted values↕
nonDelivery.option
RETURN_AFTER_RETENTION, RETURN_IMMEDIATELY, FORWARD, ABANDON — no RETURN
nonDelivery.transportMethod
AIR, MOST_ECONOMICAL
contentsType
SALE_OF_GOODS, ECOMMERCE_GOODS, COMMERCIAL_GOODS, COMMERCIAL_SAMPLE, RETURNED_GOODS, GIFT, DOCUMENTS, OTHER
serviceLevel
A japan_post.* service level code
The full enum members for any input are listed on its type page in the API reference.
Each step is independently secured. Your API key must hold the write scope for each entity in the chain (ITEM_WRITE, CARTON_WRITE, SHIPMENT_RATING_WRITE, LANDED_COST_WRITE, SHIPMENT_WRITE). The standard merchant role on a Verified Account grants all of these.
Create a single shipment
Create a single shipment
The
CreateDeclarationShipmentGraphQL workflow takes a Japan Post shipment from raw inputs to a printable label in one round trip.CreateDeclarationShipmentchains together six*Workflowmutations into a single GraphQL request. Each step builds on the data the previous steps provided, and all of them are submitted together so a complete shipment can be created in one round trip:The
Workflowmutations are designed to be chained: you don't need to thread IDs from one step into the next, and you don't need to send a separate request per step. Submit the whole document, get the finalShipmentback.When the
serviceLevelon the final step is a Japan Post service level (japan_post.*), Zonos calls the Japan Post Label API (code 52) on your behalf using your Verified Account's Later Pay Numbers, generates the label and tracking number, creates the Declaration ID, and links them — all inside that finalshipmentCreateWorkflowstep.Endpoint and authentication
The requests in this chain all use the same endpoint. What you pass in the headers depends on your setup — pick your tab.
URL:
Headers:
You ship your own orders under your own Verified Account. Authenticate as yourself — no account key needed.
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 complete
CreateDeclarationShipmentrequest you can copy and adapt — the mutation, its variables, and the response — for a single Japan Post parcel shipped DDP to the U.S. Each input is broken down in the step-by-step section below.mutation CreateDeclarationShipment($partyInput: [PartyCreateWorkflowInput!]!$itemInput: [ItemCreateWorkflowInput!]!$cartonInput: [CartonCreateWorkflowInput!]!$shipmentRatingInput: ShipmentRatingCreateWorkflowInput!$landedCostInput: LandedCostWorkFlowInput!$shipmentInput: ShipmentCreateWorkflowInput!) {partyCreateWorkflow(input: $partyInput) {idtypelocation {line1localitypostalCodecountryCode}}itemCreateWorkflow(input: $itemInput) {idnameskuamountcurrencyCodehsCode}cartonsCreateWorkflow(input: $cartonInput) {idlengthwidthheightdimensionalUnitweightweightUnit}shipmentRatingCreateWorkflow(input: $shipmentRatingInput) {idamount}landedCostCalculateWorkflow(input: $landedCostInput) {idmethodcurrencyCodeamountSubtotals {dutiestaxesfeesshippinglandedCostTotal}}shipmentCreateWorkflow(input: $shipmentInput) {idtrackingDetails {number}shipmentCartons {label {url}}}}Step-by-step
The
Statuscolumn on each table below uses these terms:1.
partyCreateWorkflowCreates the parties involved in the shipment — at minimum an
ORIGIN(where the shipment ships from) and aDESTINATION(the buyer / consignee).typeORIGINandDESTINATIONare the two this flow needs. Others (CONSIGNEE,EXPORTER,IMPORTER_OF_RECORD,PAYOR, etc.) exist but aren't used here.location.countryCodelocation.line1,locality,administrativeAreaCode,postalCodeperson.firstName,lastName,phoneperson.companyName,emailExample payload:
[ { "type": "DESTINATION", "location": { "countryCode": "US" }, "person": {} }, { "type": "ORIGIN", "location": { "countryCode": "JP" }, "person": {} } ]The response returns the created
PartyIDs and resolved address fields.2.
itemCreateWorkflowCreates the line items that make up the shipment. These are the SKUs that will appear on the commercial invoice and drive the landed-cost calculation.
currencyCodequantityamounttotalAmountis provided.totalAmountamount;amountis derived fromtotalAmount / quantity.hsCodecountryOfOriginname,descriptioncustomsDescriptionsku,productIdmeasurementsThe HS code, country of origin, and amount are the three fields that most influence the duty/tax outcome in step 5.
3.
cartonsCreateWorkflowCreates the physical packages — the boxes, polybags, or letters that will hold the items.
dimensionalUnitINCHorCENTIMETER.weight,weightUnitlength,width,heighttypePACKAGE.Each carton becomes one parcel on the carrier label in step 6. Multiple cartons → multi-piece shipment with one tracking number per carton.
4.
shipmentRatingCreateWorkflowRecords the rate quote the merchant is charging the buyer for shipping.
amount0if free.currencyCodeamount.serviceLevelCodejapan_post.air.parcel). See Japan Post service levels for the full list.displayNameThis is the rate the buyer was quoted at checkout. It feeds into the landed-cost calculation as the "shipping" subtotal so duties and taxes are computed against the correct CIF value.
5.
landedCostCalculateWorkflowRuns the duties, taxes, and fees calculation for the destination country. Uses the items, parties, and shipping cost from the prior steps.
endUseNOT_FOR_RESALEorFOR_RESALE. Some destinations apply different rates for commercial vs personal end use.tariffRateZONOS_PREFERREDif omitted. Tells Zonos which tariff source/methodology to apply.calculationMethodDDP(buyer prepays) orDDU(buyer pays at the door). UseDDPfor prepaid. Drives whetherLandedCost.amountSubtotalsincludes duty/tax.currencyCodearrivalDateThe response includes
amountSubtotals(duties,taxes,fees,shipping,landedCostTotal) — these are the numbers you display to the buyer at checkout and that get printed on the commercial invoice.6.
shipmentCreateWorkflowThe terminal step — creates the
Shipmententity, generates the carrier label, and (optionally) the commercial invoice / packing slip.For Japan Post Verified Accounts, this is also where Zonos calls the Japan Post Label API (code 52) on your behalf, injects your Later Pay Numbers, creates the Declaration ID, and links the Declaration ID to the tracking number returned by Japan Post.
Key fields:
serviceLeveljapan_post.air.ems_merchandise). Must be ajapan_post.*service level.generateLabeltrue; must betrueto return a label.contentsTypeSALE_OF_GOODS,ECOMMERCE_GOODS,COMMERCIAL_GOODS,COMMERCIAL_SAMPLE,RETURNED_GOODS,GIFT,DOCUMENTS,OTHER.nonDeliveryreferencesdeclaredValue/isDeclaredValueshipmentConsolidationIdOn
contentsType, the two most common values for Verified Account traffic areECOMMERCE_GOODS(sold to a consumer, BtoC) andCOMMERCIAL_GOODS(sold between businesses, BtoB). These set thepkgTypeZonos sends on the Japan Post label call, so the choice changes what prints on the customs declaration — it isn't just a label.nonDeliverysub-inputTells Japan Post what to do with the parcel if it can't be delivered — refused by the consignee, rejected at the border, or undeliverable as addressed.
optionaccepts exactly these four values. There is noRETURNvalue — useRETURN_AFTER_RETENTIONorRETURN_IMMEDIATELYto pick when the parcel comes back.option↕RETURN_AFTER_RETENTIONRETURN_IMMEDIATELYFORWARDABANDONThe API exposes both return variants separately; the Dashboard's Return option covers both.
transportMethodacceptsAIRorMOST_ECONOMICAL, and sets how a returned parcel travels back. It only applies to the twoRETURN_*options — the Dashboard shows the matching Return method field only when Return is selected.{ "nonDelivery": { "option": "RETURN_AFTER_RETENTION", "transportMethod": "MOST_ECONOMICAL" } }The If undeliverable picker in the Dashboard Create label dialog writes this same field, so a label created in the Dashboard and a label created through the API behave identically.
referencessub-inputThese fields print on the carrier label and/or commercial invoice. Use them to surface PO numbers, license numbers, and free-text remarks the consignee or customs authority needs to see.
invoiceNumberpurchaseOrderNumberlicenseNumbercertificateNumberpaymentConditionscustomsRemarkstaxCodeResponse
The interesting fields on the returned
Shipmentare:{ id trackingDetails { number } shipmentCartons { label { url labelImage } } }trackingDetails.numberis the Japan Post tracking number.The
labelobject can return the label two ways — request whichever fits your workflow (or both):urllabelImageSelect only the fields you need. Requesting
urlkeeps the response small; requestinglabelImagereturns the full label inline so you don't need a second round trip to fetch it. The example above requestsurl.Japan Post service levels
Pass one of these codes as
serviceLevelCodeinshipmentRatingCreateWorkflow.Service level codes use dots, not underscores. You may see the underscore form (
japan_post_air_parcel) in error messages and internal references, but it is not valid input.Air services
japan_post.air.ems_documents1-0japan_post.air.ems_merchandise1-1japan_post.air.parcel1-5japan_post.air.packet1-8japan_post.air.small_packet1-9japan_post.air.printed_matter_registered1-Ajapan_post.air.printed_matter1-Bjapan_post.air.letter_registered1-Cjapan_post.air.letter1-DSurface services
japan_post.surface.parcel2-5japan_post.surface.small_packet2-9japan_post.surface.printed_matter2-Bjapan_post.surface.letter2-DChoosing between similar services
Small packet vs. International Air Packet. Both are capped at 2 kg.
japan_post.air.packetis Japan Post's tracked small-packet service.japan_post.air.small_packetis the untracked equivalent. If you need tracking on a lightweight parcel, usejapan_post.air.packet.Registered variants. For letters and printed matter, tracking is added by the registered (書留) version of the service.
japan_post.air.printed_matterandjapan_post.air.letterdo not include it on their own.Deprecated codes
japan_post.air.epacket_lightwas International e-Packet Light. Japan Post renamed the service to International Air Packet on June 1, 2026, and expanded it to all countries and regions. The service itself is unchanged.The old code still resolves so existing integrations keep working, but use
japan_post.air.packetfor new work.Transport-mode codes
japan_post.air,japan_post.surface,japan_post.economy_air, andjapan_post.customalso resolve, but they identify a transport mode or a fallback rather than a specific mail product. Use one of the service codes above for normal shipments.Validate the code you send
An unrecognized
serviceLevelCodedoes not raise an error. The request returns HTTP 200 with noerrorsarray,serviceLevelcomes back asnull, and shipping drops out of the landed cost total — so the response looks correct while the amounts are wrong.Always assert that
shipmentRatingCreateWorkflow.serviceLevelis non-null before relying on the totals.To pull the current list at any time:
{ serviceLevels(carrier: "carrier_00004c9b-9431-4518-bfbc-b9f8476335b1") { code name } }This query takes the carrier ID. Passing the carrier code
japan_postreturns an empty list with no error.Error handling
errorsarray and abort the rest of the chain.shipmentCreateWorkflow. If a retry is needed, contact support — the recommended path is to resubmit the full mutation with corrected input.VALIDATION_INVALID_TYPE_VARIABLE{ "errors": [ { "message": "invalid type for variable: 'shipmentInput'", "extensions": { "name": "shipmentInput", "code": "VALIDATION_INVALID_TYPE_VARIABLE" } } ] }This error names the whole variable, not the field that's actually wrong. It almost always means one enum value inside that variable isn't a member of its enum — most often
nonDelivery.option,contentsType, orserviceLevel.It is not a JSON-typing problem. Quoting or unquoting your booleans and numbers won't change it, because the payload never gets that far — the enum is rejected first.
To find the bad field, check every enum-valued field in the variable against its accepted values:
nonDelivery.optionRETURN_AFTER_RETENTION,RETURN_IMMEDIATELY,FORWARD,ABANDON— noRETURNnonDelivery.transportMethodAIR,MOST_ECONOMICALcontentsTypeSALE_OF_GOODS,ECOMMERCE_GOODS,COMMERCIAL_GOODS,COMMERCIAL_SAMPLE,RETURNED_GOODS,GIFT,DOCUMENTS,OTHERserviceLeveljapan_post.*service level codeThe full enum members for any input are listed on its type page in the API reference.
Permissions
Each step is independently secured. Your API key must hold the write scope for each entity in the chain (
ITEM_WRITE,CARTON_WRITE,SHIPMENT_RATING_WRITE,LANDED_COST_WRITE,SHIPMENT_WRITE). The standard merchant role on a Verified Account grants all of these.Next steps
CartonCreateWorkflowInput ItemCreateWorkflowInput LandedCostWorkFlowInput PartyCreateWorkflowInput ShipmentCreateWorkflowInput ShipmentRatingCreateWorkflowInput
cartonsCreateWorkflow itemCreateWorkflow landedCostCalculateWorkflow partyCreateWorkflow shipmentCreateWorkflow shipmentRatingCreateWorkflow
Was this page helpful?