Integrate Cross-Border Shipments

Cross-border shipments require significantly richer data than domestic shipments. While a domestic shipment can often be booked with just a pickup, dropoff, and basic parcel information, international shipments must include detailed item-level customs data, accurate parcel weights and dimensions, trade terms, and information about the commercial parties involved in the transaction.

This guide walks through everything you need to know to create cross-border shipments through the Carriyo API, and explains how Carriyo's configuration hierarchy lets you choose what to pass per shipment versus what to default at the carrier account level.

When to use this guide

Use this guide when you are:

  • Shipping goods across international borders that require customs clearance.
  • Integrating with carriers that require commercial invoice data (DHL Express, FedEx, UPS, DB Schenker, etc.).
  • Shipping to or from regions with specific regulatory requirements (e.g. EU IOSS, GCC VAT, India GST).
  • Handling DDP (Delivered Duty Paid) or DDU (Delivered Duty Unpaid) flows where duty responsibility must be declared.

If your shipments are purely domestic and don't cross customs boundaries, the standard Create Shipment documentation is sufficient.


How Carriyo resolves cross-border data

Before diving into the individual fields, it's important to understand how Carriyo resolves customs-related data at booking time. Carriyo uses a configuration hierarchy — you don't necessarily need to pass every cross-border field on every shipment. Instead, you can configure defaults at the carrier account level, and only pass shipment-level data when it differs.

The resolution order is:

  1. Shipment-level data (highest priority) — If you pass a value in the shipment's customs object, it is always used.
  2. Carrier account properties (fallback) — If the shipment doesn't include the field, Carriyo checks the carrier account's configured properties for a default value.
  3. Smart defaults (lowest priority) — For certain parties, additional fallback logic applies. For example, if Seller defaults to pickup is enabled on the carrier account, the seller details will be derived from the shipment's pickup address when no explicit seller is configured. Similarly, Buyer defaults to dropoff derives the buyer from the dropoff address.

This means that for merchants who always ship from the same entity with the same tax registrations, the seller, exporter, and incoterms can be configured once on the carrier account — and individual shipments only need to carry the data that varies per order (items, parcels, buyer/dropoff).

Example: DHL Express — A DHL carrier account can be configured via the Carriyo dashboard with default values for the incoterm, seller, buyer, exporter, and importer — including full addresses and registration numbers. See Carrier Account configuration below for details.


Cross-border data checklist

1. Item-level customs data

Each item in the items[] array must carry enough detail for customs declaration and commercial invoice generation.

Required item fields

Field Shipment path Notes
Description items[].description Human-readable description for customs forms (e.g. "Cotton T-shirt, size M, blue"). Required at confirm.
SKU items[].sku Unique item/SKU identifier from your catalog. Required at confirm.
Quantity items[].quantity Integer, must be >= 1. Required at confirm.
Unit price items[].price.amount, items[].price.currency Price per unit. Currency as ISO 4217 code (e.g. USD, AED, EUR). Required at confirm.
HS code items[].hs_code The Harmonized System commodity code. Required by most carriers and customs authorities for classification and duty calculation. Typically 6-10 digits.
Country of origin items[].origin_country Two-letter ISO 3166-1 alpha-2 code for the country where the item was manufactured (e.g. CN, IN, US).
Item weight items[].weight.value, items[].weight.unit Net weight of a single unit. Unit is typically kg. Used for customs value calculations and documentation.

Tip: The description field appears directly on customs forms and commercial invoices. Vague descriptions like "Clothing" or "Goods" can cause customs delays. Be specific: "Men's cotton polo shirt" is better than "Shirt".

Additional item fields for compliance

Depending on the carrier, destination country, or the nature of the goods, you may also need:

Field Shipment path When needed
Cost price items[].cost.amount, items[].cost.currency The unit cost of the item. Useful when the selling price (price) is zero — for example, samples or promotional items. Customs authorities require a monetary value for declaration even when the item is not being sold. In such cases, set price to 0 and provide the actual cost here so it can be used on the commercial invoice and customs declaration.
Dangerous goods items[].dangerous_goods Set to true if the item is classified as hazardous goods (e.g. perfumes, aerosols, certain chemicals). Triggers carrier-specific DG handling.
Battery details items[].battery.material_type, items[].battery.packing_type Required when shipping items containing lithium batteries. material_type values: lithium_ion, lithium_metal. packing_type values: contained_in_equipment, packed_with_equipment, stand_alone.
Taxes items[].taxes[] Pre-calculated tax amounts for the item, if available from your tax engine.
Duties items[].duties[] Pre-calculated duty amounts for the item.
Manufacturer ID items[].manufacturer_id Manufacturer reference. Required by some carriers for specific destination countries.
Material composition items[].material_composition Material details (e.g. "100% cotton", "polyester blend"). Relevant for textile and apparel shipments where customs classification depends on material.

2. Parcel-level details

Parcels define the physical packages being shipped. Even when item data is complete, carrier booking may fail if parcel weight and dimensions are missing or inaccurate.

Field Shipment path Notes
Parcel weight parcels[].weight.value, parcels[].weight.unit The actual packed weight of the parcel including packaging material. Required for rating, booking, and label generation.
Parcel dimensions parcels[].dimension.width, parcels[].dimension.height, parcels[].dimension.depth, parcels[].dimension.unit Physical dimensions of the package. Used to calculate volumetric (dimensional) weight. Carriers charge based on whichever is greater: actual weight or volumetric weight.
Item-to-parcel mapping parcels[].parcel_items[].sku, parcels[].parcel_items[].quantity Specifies which items (and how many of each) are in each parcel. Critical for multi-parcel shipments where customs documentation must accurately reflect the contents of each package.

Why parcel weight matters separately from item weight: The parcel weight should reflect the total packed weight — including packaging materials, filler, and the box itself. The sum of individual item weights will typically be less than the parcel weight. Carriers use the parcel weight for rating; customs authorities use item weights for duty calculation.

Volumetric weight: Most international carriers calculate chargeable weight as the greater of actual weight or volumetric weight. Volumetric weight = (Width x Height x Depth) / volumetric divisor (typically 5000 for cm/kg). If you don't provide dimensions, some carriers will reject the booking; others may apply default dimensions that result in higher charges.

3. Shipment-level customs context

The customs object on the shipment carries trade terms, value declarations, and customs-specific instructions.

Field Shipment path Notes
Incoterms customs.incoterms International Commercial Terms defining the responsibilities of buyer and seller. See Incoterms reference below.
Declared value customs.declared_value.amount, customs.declared_value.currency Optional override of the total customs value. If omitted, Carriyo or the carrier typically derives this from the sum of items[].price.amount * items[].quantity. Use this when you need to declare a different value than the item total.
Customs instructions customs.instructions Free-text handling notes for customs processing (e.g. "Fragile — handle with care", "Temperature sensitive").
Declaration statement customs.declaration_statement Formal legal text for the customs declaration (e.g. "I hereby certify that the information on this invoice is true and correct and that the contents of this shipment are as stated above.").

4. Customs parties

For domestic shipments, the pickup and dropoff addresses are sufficient. For international shipments, customs authorities and carriers may require additional parties to be identified. These parties appear on the commercial invoice and customs declaration documents.

Party Shipment path Role
Seller customs.seller The entity selling the goods. Often the merchant or warehouse operator. Appears on the commercial invoice as the invoicing party.
Buyer customs.buyer The entity purchasing the goods. Typically the end customer. The "sold to" party on the commercial invoice.
Importer customs.importer The Importer of Record (IOR) — the entity responsible for clearing goods through customs at the destination country. May carry specific tax registration numbers (VAT, IOSS, EOR).
Exporter customs.exporter The Exporter of Record (EOR) — the entity responsible for export compliance and documentation in the origin country.
Broker customs.broker The customs broker handling clearance formalities on behalf of the importer or exporter. Used by carriers like FedEx for broker-assisted clearance.

When are these parties needed?

Not every shipment requires all five parties. Here's a practical guide:

  • Seller + Buyer : Required by most carriers for any cross-border shipment. These are the core commercial invoice parties.
  • Exporter : Often the same as the seller, but may differ if a third-party logistics provider handles export. Required by carriers like DHL Express for the customs declaration.
  • Importer : Often the same as the buyer, but critical when a dedicated importer of record handles customs clearance at the destination. The importer typically carries the tax/duty registration numbers for the destination country.
  • Broker : Used when a customs broker is involved in clearance. Common with FedEx shipments that use broker-assisted import.

Don't have all the party details? Carriyo supports smart defaults. For example, if the carrier account has Seller defaults to pickup enabled, the seller will be automatically derived from the pickup address. Similarly, Buyer defaults to dropoff derives the buyer from the dropoff address. This is useful when the seller is always the warehouse (pickup) and the buyer is always the consignee (dropoff).

Party field structure

Each customs party uses the same address structure:

Field JSON path (relative to party) Notes
Contact name contact_name Full name of the contact person. Required at confirm.
Company name company_name Legal entity or business name. Only needed when it differs from contact_name — for domestic shipments, the company name is often passed in contact_name directly. More relevant for cross-border where customs forms distinguish the two.
Phone contact_phone Contact phone number with country code.
Email contact_email Contact email address.
Address line 1 address1 Primary street address.
Address line 2 address2 Additional address details (suite, floor, etc.).
City city City name.
State / Province state State, province, or region.
Postal code postcode Postal or ZIP code.
Country country Two-letter ISO 3166-1 alpha-2 country code. Required at confirm.
Personal ID personal_id.id, personal_id.type Government-issued identification (passport number, national ID). Required for customs clearance in some countries (e.g. Brazil CPF, South Korea PCC).
Registration numbers registration_numbers[] Tax and regulatory identifiers. See Registration numbers below.

Registration numbers

Registration numbers are tax and regulatory identifiers critical for customs clearance. Each customs party can carry multiple registration numbers — for example, a seller might have both a VAT number and an IOSS number.

Copy
Copied
"registration_numbers": [
  {
    "type_code": "VAT",
    "value": "GB123456789",
    "issuer_country_code": "GB"
  },
  {
    "type_code": "IOSS",
    "value": "IM1234567890",
    "issuer_country_code": "IE"
  }
]

Each registration number has three fields:

Field Description
type_code The type of registration. See supported types below.
value The actual registration number value.
issuer_country_code The two-letter ISO country code of the issuing authority.

Supported registration number types:

Type code Full name Common use
VAT Value Added Tax Most international shipments. Required in EU, GCC, UK.
IOSS Import One-Stop Shop EU imports under EUR 150. Placed on the seller or importer.
EOR Economic Operator Registration (EORI) EU/UK customs clearance. Required for commercial importers.
EIN Employer Identification Number US-based entities.
GST Goods and Services Tax India, Australia, Singapore, and other GST jurisdictions.
PAN Permanent Account Number India — required for customs clearance.
SSN Social Security Number Individual identification in some jurisdictions.
DUN Dun & Bradstreet Number Business identification.
FED Federal Tax ID Federal-level tax identification.
STA State Tax ID State-level tax identification.
SDT State Department of Taxation State tax authority registration.
INN Taxpayer Identification Number Russia.
KPP Tax Registration Reason Code Russia.
OGR Primary State Registration Number Russia.
OKP Russian Classification of Products Russia.
CNP Cod Numeric Personal Romania — personal identification code.
IE Inscrição Estadual Brazil — state-level tax registration.

Common scenarios:

  • Shipping to the EU (under EUR 150): The seller's or importer's IOSS number should be provided. This enables simplified customs clearance and ensures VAT is collected at the point of sale rather than at import.
  • Shipping to the UK: The importer should have an EOR (EORI) number. The seller may need a UK VAT number if registered.
  • Shipping to/from India: PAN and GST numbers are commonly required on the exporter and importer.
  • Shipping to/from GCC countries: VAT registration numbers are required for commercial shipments.

Incoterms reference

Incoterms (International Commercial Terms) define who is responsible for shipping costs, insurance, duties, and risk at each stage of the shipment. The customs.incoterms field tells the carrier which trade terms apply to the shipment.

Supported values

Code Full name Who pays duties & taxes? Who bears shipping risk?
EXW Ex Works Buyer Buyer from seller's premises
FCA Free Carrier Buyer Buyer after handover to carrier
FAS Free Alongside Ship Buyer Buyer after goods placed alongside vessel
FOB Free on Board Buyer Buyer after goods loaded on vessel
CFR Cost and Freight Buyer Buyer after goods loaded on vessel
CIF Cost, Insurance, and Freight Buyer Buyer after goods loaded on vessel
CPT Carriage Paid To Buyer Buyer after handover to carrier
CIP Carriage and Insurance Paid To Buyer Buyer after handover to carrier
DAP Delivered at Place Buyer Seller until arrival at destination
DPU Delivered at Place Unloaded Buyer Seller until unloaded at destination
DDP Delivered Duty Paid Seller Seller until delivery
DDU Delivered Duty Unpaid Buyer Seller until arrival at destination
DAT Delivered at Terminal Buyer Seller until unloaded at terminal (replaced by DPU in Incoterms 2020)
DAF Delivered at Frontier Buyer Seller until frontier (legacy)
DEQ Delivered Ex Quay Buyer Seller until unloaded at quay (legacy)
DES Delivered Ex Ship Buyer Seller until arrival at port (legacy)

Choosing the right incoterm for e-commerce

For most e-commerce cross-border shipments, the practical choice comes down to two options:

  • DAP (Delivered at Place) — The seller ships to the destination and the buyer pays any import duties and taxes upon delivery. This is the most common incoterm for international e-commerce. The buyer may be asked to pay duties at the door, which can lead to refused deliveries if unexpected.
  • DDP (Delivered Duty Paid) — The seller covers all costs including import duties, taxes, and customs clearance fees. This provides a better customer experience (no surprise charges at delivery) but the seller assumes full duty and tax liability. Requires the seller or their agent to have the ability to pay duties in the destination country.

Tip: If you are seeing high rates of refused deliveries on international shipments, consider switching from DAP to DDP and factoring duties into your product pricing or checkout flow.

Carrier-specific incoterm support

Not all carriers support all incoterms. Carriyo validates the incoterm against the carrier's supported values at booking time. Here are some examples:

Carrier Supported incoterms
DHL Express CFR, CIF, CIP, CPT, DAF, DAP, DAT, DDP, DDU, DPU, DEQ, DES, EXW, FAS, FCA, FOB
FedEx DAP, DAT, DDP, DDU, EXW
UPS CFR, CIF, CIP, CPT, DAF, DDP, DDU, DEQ, DES, EXW, FAS, FCA, FOB
DHL eCommerce DDP, DDU
AJEX DDP, DDU
GLS DDP, DDU
DB Schenker CFR, CIF, CIP, CPT, DAF, DAP, DAT, DDP, DDU, DEQ, DES, DPU, EXW, FAS, FCA, FOB

If you pass an unsupported incoterm for a given carrier, the booking will fail with an error indicating which values are accepted.

Incoterm resolution: shipment vs. carrier account

Incoterms follow Carriyo's standard configuration hierarchy:

  1. If customs.incoterms is set on the shipment, that value is used.
  2. If not set on the shipment, the carrier account's configured incoterm default is used (e.g. INCOTERM: "DDP" in the DHL carrier account properties).
  3. If neither is configured, the carrier booking proceeds without an incoterm (which may cause a booking failure if the carrier requires one).

When to pass it on the shipment: When you have mixed incoterm requirements — for example, DDP for some destinations and DAP for others — pass the incoterm per shipment.

When to configure it on the carrier account: When all shipments through a given carrier account use the same trade terms. This is common when a carrier account is dedicated to a specific trade lane (e.g. a DHL account used exclusively for DDP shipments from UAE to EU).


Configuring defaults on the carrier account

Many cross-border fields that remain the same across all shipments for a given carrier account can be configured as defaults rather than passed on every shipment. This reduces the payload size and ensures consistency.

Carrier account configuration is managed through the Carriyo dashboard. Each carrier has its own set of supported configuration fields — the available settings depend on the carrier's specification and what Carriyo supports for that integration. These settings are not self-service via the API.

The following are examples of what can typically be configured at the carrier account level for cross-border flows:

Incoterm default

A default incoterm (e.g. DDP, DAP) can be set on the carrier account. When configured, it applies automatically to all shipments booked through that account unless the shipment explicitly passes customs.incoterms.

Customs party defaults (seller, buyer, exporter, importer)

For carriers that require customs parties (such as DHL Express), the full details of each party — including name, company, address, and registration numbers — can be pre-configured on the carrier account. This is common when:

  • The seller/exporter is always the same entity (your company) across all shipments.
  • The importer is a fixed third-party agent handling customs clearance at the destination.

When these defaults are configured, you don't need to pass the corresponding customs.seller, customs.exporter, or customs.importer objects on each shipment — Carriyo fills them in from the carrier account at booking time.

Smart party defaults

Some carriers (such as DHL Express) support smart fallback behavior that can be enabled on the carrier account via the Carriyo dashboard:

  • Seller defaults to pickup — If no seller is configured on the shipment or the carrier account, the pickup address is used as the seller.
  • Buyer defaults to dropoff — If no buyer is configured on the shipment or the carrier account, the dropoff address is used as the buyer.

This is particularly useful for standard e-commerce flows where the seller is always the warehouse (pickup) and the buyer is always the end customer (dropoff). With these defaults enabled on the carrier account, you may not need to pass seller or buyer details at all — Carriyo derives them from the shipment's pickup and dropoff addresses.

Other carrier-specific settings

Depending on the carrier, additional cross-border settings may be available at the carrier account level. Examples include:

  • DHL Express : customs declarable flag, invoice type and template, invoice signatory details, shipper and receiver registration numbers.
  • FedEx : customs broker details (name, address, account number), terms of sale.

Note: The available configuration fields vary by carrier. Work with your Carriyo support team to set up the carrier account for your cross-border requirements. They will help you configure the appropriate settings based on the carrier's specification and your specific trade lanes.


Recommended integration flow

Step 1: Configure carrier account defaults

Before you start sending cross-border shipments, configure your carrier account with the static cross-border data:

  • Default incoterm, if all shipments through this account use the same trade terms.
  • Seller and exporter details, including addresses and tax registration numbers.
  • Smart defaults (seller-to-pickup, buyer-to-dropoff) if appropriate for your flow.
  • Any carrier-specific customs settings (e.g. customs declarable flag for DHL).

Step 2: Create shipments with per-order data

When creating a shipment, include the data that varies per order:

  • items[] : Complete item details including description , sku , quantity , price , hs_code , origin_country , and weight .
  • parcels[] : Accurate packed weight, dimensions, and item-to-parcel mapping.
  • customs.buyer or customs.importer : If the buyer or importer differs from the dropoff address (or if smart defaults are not enabled).
  • customs.incoterms : Only if it differs from the carrier account default.
  • customs.declaration_statement : If required by your carrier or lane.

Step 3: Confirm and monitor

  1. Confirm the shipment once fulfillment and parcelization are final using Confirm Shipment . Carriyo validates all required fields at confirmation time.
  2. Monitor for errors. Common cross-border booking failures include:
    • Missing or invalid hs_code
    • Missing origin_country on items
    • Missing description on items
    • Missing or inaccurate parcel weight or dimension
    • Missing registration numbers on customs parties
    • Unsupported incoterm for the carrier
  3. Correct and retry. Use Patch Shipment to fix individual fields without replacing the entire shipment payload, then retry the booking using Reprocess Shipment .

See Shipment Validation Errors and Shipment Error Codes for error reference.


Example: Cross-border shipment with full customs data

The example below shows a complete cross-border shipment from UAE to UK, with two items, one parcel, and full customs data including parties and registration numbers.

Copy
Copied
{
  "merchant": "YOUR-MERCHANT-ID",
  "entity_type": "FORWARD",
  "pickup": {
    "contact_name": "Acme Fashion Warehouse",
    "company_name": "Acme Fashion Ltd",
    "contact_phone": "+971501234567",
    "address1": "Dubai Internet City, Building 12",
    "city": "Dubai",
    "country": "AE",
    "postcode": "00000"
  },
  "dropoff": {
    "contact_name": "Jane Smith",
    "contact_phone": "+447700900123",
    "contact_email": "jane.smith@example.com",
    "address1": "42 King's Road",
    "city": "London",
    "state": "England",
    "country": "GB",
    "postcode": "SW3 4ND"
  },
  "items": [
    {
      "description": "Women's cotton T-shirt, size M, navy blue",
      "sku": "TSHIRT-W-M-NAVY",
      "quantity": 2,
      "price": { "amount": 25.00, "currency": "USD" },
      "weight": { "value": 0.2, "unit": "kg" },
      "hs_code": "610910",
      "origin_country": "IN"
    },
    {
      "description": "Wireless Bluetooth earbuds with charging case",
      "sku": "EARBUDS-BT-001",
      "quantity": 1,
      "price": { "amount": 89.99, "currency": "USD" },
      "weight": { "value": 0.15, "unit": "kg" },
      "hs_code": "851830",
      "origin_country": "CN",
      "dangerous_goods": false,
      "battery": {
        "material_type": "lithium_ion",
        "packing_type": "contained_in_equipment"
      }
    }
  ],
  "parcels": [
    {
      "weight": { "value": 0.9, "unit": "kg" },
      "dimension": {
        "width": 30,
        "height": 20,
        "depth": 15,
        "unit": "cm"
      },
      "parcel_items": [
        { "sku": "TSHIRT-W-M-NAVY", "quantity": 2 },
        { "sku": "EARBUDS-BT-001", "quantity": 1 }
      ]
    }
  ],
  "customs": {
    "incoterms": "DAP",
    "declaration_statement": "I hereby certify that the information on this invoice is true and correct and that the contents of this shipment are as stated above.",
    "seller": {
      "contact_name": "Ahmed Al Rashid",
      "company_name": "Acme Fashion Ltd",
      "contact_phone": "+971501234567",
      "contact_email": "exports@acmefashion.com",
      "address1": "Dubai Internet City, Building 12",
      "city": "Dubai",
      "country": "AE",
      "postcode": "00000",
      "registration_numbers": [
        {
          "type_code": "VAT",
          "value": "100234567890003",
          "issuer_country_code": "AE"
        }
      ]
    },
    "buyer": {
      "contact_name": "Jane Smith",
      "contact_phone": "+447700900123",
      "contact_email": "jane.smith@example.com",
      "address1": "42 King's Road",
      "city": "London",
      "state": "England",
      "country": "GB",
      "postcode": "SW3 4ND"
    },
    "exporter": {
      "contact_name": "Ahmed Al Rashid",
      "company_name": "Acme Fashion Ltd",
      "contact_phone": "+971501234567",
      "contact_email": "exports@acmefashion.com",
      "address1": "Dubai Internet City, Building 12",
      "city": "Dubai",
      "country": "AE",
      "postcode": "00000",
      "registration_numbers": [
        {
          "type_code": "EOR",
          "value": "AEXXXXXXXXX",
          "issuer_country_code": "AE"
        }
      ]
    },
    "importer": {
      "contact_name": "Jane Smith",
      "company_name": "Jane Smith",
      "contact_phone": "+447700900123",
      "address1": "42 King's Road",
      "city": "London",
      "state": "England",
      "country": "GB",
      "postcode": "SW3 4ND",
      "registration_numbers": [
        {
          "type_code": "EOR",
          "value": "GB205672212000",
          "issuer_country_code": "GB"
        }
      ]
    }
  }
}

Simplified version using carrier account defaults

If the carrier account is configured with seller, exporter, incoterm, and smart defaults (Seller defaults to pickup enabled, Buyer defaults to dropoff enabled), the same shipment can be created with a much leaner payload — only the per-order data:

Copy
Copied
{
  "merchant": "YOUR-MERCHANT-ID",
  "entity_type": "FORWARD",
  "pickup": {
    "contact_name": "Acme Fashion Warehouse",
    "company_name": "Acme Fashion Ltd",
    "contact_phone": "+971501234567",
    "address1": "Dubai Internet City, Building 12",
    "city": "Dubai",
    "country": "AE",
    "postcode": "00000"
  },
  "dropoff": {
    "contact_name": "Jane Smith",
    "contact_phone": "+447700900123",
    "contact_email": "jane.smith@example.com",
    "address1": "42 King's Road",
    "city": "London",
    "state": "England",
    "country": "GB",
    "postcode": "SW3 4ND"
  },
  "items": [
    {
      "description": "Women's cotton T-shirt, size M, navy blue",
      "sku": "TSHIRT-W-M-NAVY",
      "quantity": 2,
      "price": { "amount": 25.00, "currency": "USD" },
      "weight": { "value": 0.2, "unit": "kg" },
      "hs_code": "610910",
      "origin_country": "IN"
    },
    {
      "description": "Wireless Bluetooth earbuds with charging case",
      "sku": "EARBUDS-BT-001",
      "quantity": 1,
      "price": { "amount": 89.99, "currency": "USD" },
      "weight": { "value": 0.15, "unit": "kg" },
      "hs_code": "851830",
      "origin_country": "CN",
      "battery": {
        "material_type": "lithium_ion",
        "packing_type": "contained_in_equipment"
      }
    }
  ],
  "parcels": [
    {
      "weight": { "value": 0.9, "unit": "kg" },
      "dimension": {
        "width": 30,
        "height": 20,
        "depth": 15,
        "unit": "cm"
      },
      "parcel_items": [
        { "sku": "TSHIRT-W-M-NAVY", "quantity": 2 },
        { "sku": "EARBUDS-BT-001", "quantity": 1 }
      ]
    }
  ]
}

In this version, the seller and exporter are derived from carrier account defaults, the buyer is derived from the dropoff address, and the incoterm comes from the carrier account's configured default. The customs object is omitted entirely.


Troubleshooting

Symptom Likely cause Fix
Booking fails with "incoterm not supported" Incoterm value not accepted by this carrier Check the carrier-specific incoterm table and use a supported value.
Customs hold or clearance delay Missing or vague item description, missing hs_code, or incorrect origin_country Ensure all items have specific descriptions, accurate HS codes, and correct origin country.
"Missing registration number" error Carrier requires a tax ID on one of the customs parties Add the appropriate registration_numbers to the seller, buyer, importer, or exporter.
Carrier charges higher than expected Missing parcel dimension causing estimated volumetric weight Always provide accurate parcel dimensions.
"Missing customs data" error Carrier requires customs declaration but no customs data was provided Ensure the carrier account is configured for customs declarations , and that items have hs_code and origin_country.
Duties charged to wrong party Incorrect incoterm (e.g. DDP when it should be DAP, or vice versa) Verify the incoterm matches your commercial agreement with the buyer.
Shipment rejected at origin Missing exporter registration numbers or export license Add EOR or other required registration numbers to customs.exporter.
Refused delivery / customer complaints about duty charges Customer unaware of import duty liability under DAP/DDU Consider switching to DDP or adding duty estimates to your checkout flow.