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:
-
Shipment-level data (highest priority)
— If you pass a value in the shipment's
customsobject, it is always used. - Carrier account properties (fallback) — If the shipment doesn't include the field, Carriyo checks the carrier account's configured properties for a default value.
-
Smart defaults (lowest priority)
— For certain parties, additional fallback logic applies. For example, if
Seller defaults to pickupis enabled on the carrier account, the seller details will be derived from the shipment'spickupaddress when no explicit seller is configured. Similarly,Buyer defaults to dropoffderives the buyer from thedropoffaddress.
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
descriptionfield 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 pickupenabled, the seller will be automatically derived from the pickup address. Similarly,Buyer defaults to dropoffderives 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. |
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.
"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
IOSSnumber 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 UKVATnumber if registered. -
Shipping to/from India:
PANandGSTnumbers are commonly required on the exporter and importer. -
Shipping to/from GCC countries:
VATregistration 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:
-
If
customs.incotermsis set on the shipment, that value is used. -
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). - 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
pickupaddress is used as the seller. -
Buyer defaults to dropoff
— If no buyer is configured on the shipment or the carrier account, the
dropoffaddress 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 includingdescription,sku,quantity,price,hs_code,origin_country, andweight. -
parcels[]: Accurate packed weight, dimensions, and item-to-parcel mapping. -
customs.buyerorcustoms.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
- Confirm the shipment once fulfillment and parcelization are final using Confirm Shipment . Carriyo validates all required fields at confirmation time.
-
Monitor for errors.
Common cross-border booking failures include:
-
Missing or invalid
hs_code -
Missing
origin_countryon items -
Missing
descriptionon items -
Missing or inaccurate parcel
weightordimension - Missing registration numbers on customs parties
- Unsupported incoterm for the carrier
-
Missing or invalid
- 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.
{
"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:
{
"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. |