Cross-border shipping
International shipments require richer data than domestic ones. A
domestic shipment can be booked with little more than a pickup,
dropoff, and basic parcel information. International shipments must also carry item-level customs data
(HS codes, country of origin, declared values), accurate parcel
weights and dimensions, and trade terms (incoterms). They also
require information about the commercial parties involved
(seller, buyer, importer, exporter, broker).
This page describes the model. For the API walkthrough, see Recipe → ship cross-border.
How Carriyo resolves cross-border data
Carriyo uses a configuration hierarchy so you don't have to pass every cross-border field on every shipment. Defaults configured on the carrier account fill in any field the shipment omits. A small set of "smart defaults" go further by deriving parties from the pickup and dropoff addresses.
Resolution order, highest priority first:
- Shipment-level data. Anything in the shipment's
customsobject always wins. - Carrier-account properties. Defaults configured on the carrier account: incoterm, party details, registration numbers, carrier-specific flags.
- Smart defaults. Fallback rules like Seller defaults to pickup or Buyer defaults to dropoff. They derive parties from the shipment's pickup and dropoff addresses when nothing else is configured.
For merchants who always ship from the same entity with the same tax registrations, configure the seller, exporter, and incoterm once on the carrier account. Individual shipments then only need to carry the data that varies per order (items, parcels, buyer/dropoff).
The cross-border data checklist
1. Item-level customs data
Each entry in items[] must carry enough detail for customs
declaration and commercial invoice generation.
| Field | Path | Notes |
|---|---|---|
| Description | items[].description | Specific human-readable description for customs forms. Vague descriptions ("Goods", "Clothing") cause customs delays. Required at confirm. |
| SKU | items[].sku | Unique catalogue identifier. Required at confirm. |
| Quantity | items[].quantity | Integer ≥ 1. Required at confirm. |
| Unit price | items[].price.amount, items[].price.currency | Per-unit price; currency as ISO 4217. Required at confirm. |
| HS code | items[].hs_code | Harmonized System commodity code (typically 6–10 digits). Required by most carriers and customs authorities. |
| Country of origin | items[].origin_country | ISO 3166-1 alpha-2 of the manufacturing country. |
| Item weight | items[].weight.value, items[].weight.unit | Net weight per unit. Used for customs value calculations. |
Additional item fields when relevant: cost (for zero-priced
samples that still need a customs value), dangerous_goods,
battery.material_type and battery.packing_type (for lithium
batteries), taxes[], duties[], manufacturer_id,
material_composition.
2. Parcel-level details
Parcels define the physical packages. Even with complete item data, carrier booking can fail if parcel weight and dimensions are missing.
| Field | Path | Notes |
|---|---|---|
| Parcel weight | parcels[].weight.value, parcels[].weight.unit | Total packed weight including packaging. Required for rating, booking, and label generation. |
| Parcel dimensions | parcels[].dimension.{width,height,depth,unit} | Used to compute volumetric weight. Carriers charge on the greater of actual vs volumetric. |
| Item-to-parcel mapping | parcels[].parcel_items[].{sku,quantity} | Which items (and how many) are in each parcel. Critical for multi-parcel shipments where customs documentation must reflect each package's contents. |
The parcel weight should reflect the total packed weight (packaging + filler + box + items), not the sum of item weights. Carriers use parcel weight for rating; customs uses item weights for duty calculation.
3. Shipment-level customs context
The customs object on the shipment carries trade terms,
declared value overrides, and customs-specific instructions.
| Field | Path | Notes |
|---|---|---|
| Incoterms | customs.incoterms | International Commercial Terms. See Incoterms below. |
| Declared value | customs.declared_value.{amount,currency} | Optional override of the total customs value. If omitted, derived from items[].price × items[].quantity. |
| Customs instructions | customs.instructions | Free-text handling notes for customs processing. |
| Declaration statement | customs.declaration_statement | Formal legal text for the customs declaration. |
4. Customs parties
For domestic shipments, pickup and dropoff are sufficient.
For international shipments, customs authorities and carriers may
require you to identify additional parties. These appear on the
commercial invoice and customs declaration documents.
| Party | Path | Role |
|---|---|---|
| Seller | customs.seller | The entity selling the goods. 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 invoice. |
| Importer | customs.importer | Importer of Record, responsible for clearing goods through customs at the destination. Typically carries destination-country tax/duty registration numbers (VAT, IOSS, EOR). |
| Exporter | customs.exporter | Exporter of Record, responsible for export compliance and documentation in the origin country. |
| Broker | customs.broker | Customs broker handling clearance formalities. Used by carriers like FedEx for broker-assisted clearance. |
Practical guide to which parties you need:
- Seller + Buyer are required by most carriers for any cross-border shipment.
- Exporter is often the same as the seller, but may differ if a third-party logistics provider handles export. Required by carriers like DHL Express.
- Importer is often the same as the buyer, but critical when a dedicated importer of record handles clearance.
- Broker is used when a customs broker is involved, common with FedEx's broker-assisted import.
Party structure
Every party uses the standard address structure (contact_name,
company_name, contact_phone, contact_email, address1,
address2, city, state, postcode, country) plus two
cross-border-specific fields:
personal_id.{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[]: tax and regulatory identifiers.
Registration numbers
Each 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"
}
]
Supported type_code values:
| Code | Full name | Common use |
|---|---|---|
VAT | Value Added Tax | EU, GCC, UK, most international shipments |
IOSS | Import One-Stop Shop | EU imports under EUR 150 |
EOR | Economic Operator Registration (EORI) | EU/UK customs clearance |
EIN | Employer Identification Number | US-based entities |
GST | Goods and Services Tax | India, Australia, Singapore, etc. |
PAN | Permanent Account Number | India |
SSN | Social Security Number | US individual ID |
DUN | Dun & Bradstreet Number | Business identification |
FED | Federal Tax ID | Federal-level US |
STA | State Tax ID | State-level US |
SDT | State Department of Taxation | US state |
INN / KPP / OGR / OKP | (Russia-specific) | Russian customs |
CNP | Cod Numeric Personal | Romania |
IE | Inscrição Estadual | Brazil state-level tax |
Common scenarios:
- EU under EUR 150. Supply seller's or importer's
IOSS. - United Kingdom. Importer should carry
EOR(EORI); seller may need a UKVATnumber if registered. - India.
PANandGSTon exporter and importer. - GCC.
VATregistrations on the commercial parties.
Incoterms
customs.incoterms declares which International Commercial
Terms apply: who's responsible for shipping costs, insurance,
duties, and risk at each stage.
Supported values
| Code | Full name | Duties & taxes | 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 / DEQ / DES | (legacy) | Buyer | Various legacy delivered-at-* terms |
Choosing for e-commerce
For most cross-border e-commerce, the practical choice is between two:
DAP(Delivered at Place). Seller ships to the destination; buyer pays import duties and taxes on delivery. Most common, but the buyer may be surprised by duties at the door, leading to refused deliveries.DDP(Delivered Duty Paid). Seller covers all costs including duties, taxes, and clearance fees. Better customer experience, but the seller assumes full duty and tax liability and needs the ability to pay duties in the destination country.
If you're seeing high refusal rates on international shipments, switching from DAP to DDP and pricing duties into your checkout flow is the standard remedy.
Carrier-specific incoterm support
Not every carrier supports every incoterm. Carriyo validates the incoterm against the carrier's accepted values at booking time. 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, booking fails with an error listing the accepted values.
Incoterm resolution
Incoterms follow the standard configuration hierarchy:
- If
customs.incotermsis set on the shipment, that wins. - Otherwise, the carrier account's configured default applies.
- If neither is set, the carrier booking proceeds without an incoterm (which may fail if the carrier requires one).
Pass per shipment when you have mixed requirements: DDP for some destinations, DAP for others. Configure on the carrier account when all shipments through that account use the same trade terms. This is typical for accounts dedicated to a specific lane (for example, a DHL account used exclusively for DDP shipments from UAE to EU).
Carrier account defaults
Carrier account configuration is managed in the Dashboard. Each carrier exposes a different set of supported settings, depending on the carrier's specification and what Carriyo's integration supports. Three categories show up most often for cross-border flows:
Incoterm default
A default incoterm (e.g. DDP, DAP) set on the carrier
account applies to every shipment booked through it unless the
shipment explicitly passes customs.incoterms.
Customs party defaults
For carriers that require customs parties (like DHL Express), the full details of each party (name, company, address, registration numbers) can be pre-configured on the carrier account. This is common when:
- The seller / exporter is always the same entity (your company).
- The importer is a fixed third-party agent handling customs clearance at the destination.
When defaults are configured, you don't pass the corresponding
customs.seller, customs.exporter, or customs.importer
objects on each shipment. Carriyo fills them in at booking time.
Smart party defaults
Some carriers (DHL Express among them) support fallback rules that derive parties from the shipment's pickup/dropoff:
- 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, the
dropoffaddress is used as the buyer.
Useful for standard e-commerce flows where the seller is always the warehouse and the buyer is always the end customer. With both enabled, you may not need to pass seller or buyer at all.
Other carrier-specific settings
Examples of additional cross-border settings exposed at the carrier account level:
- 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.
The available fields vary by carrier. Work with your Carriyo support team to set up the carrier account for your cross-border requirements.
Common pitfalls
| Symptom | Likely cause | Fix |
|---|---|---|
| Booking fails with "incoterm not supported" | Incoterm value not accepted by this carrier | Use a value from the Carrier-specific support table. |
| Customs hold or clearance delay | Vague item description, missing hs_code, or wrong origin_country | Specific descriptions, accurate HS codes, correct origin country. |
| "Missing registration number" error | Carrier requires a tax ID on a customs party | Add registration_numbers to seller / buyer / importer / exporter as needed. |
| Carrier charge higher than expected | Missing parcel dimension causing carrier to apply default volumetric weight | Always provide accurate parcel dimensions. |
| Duties charged to the wrong party | Wrong incoterm (DDP vs DAP) | Check the incoterm matches your commercial agreement. |
| Shipment rejected at origin | Missing exporter registration numbers or export license | Add EOR or other required registrations to customs.exporter. |
| Refused delivery / customer complaints about duty charges | Customer unaware of import duty under DAP/DDU | Switch to DDP and price duties into checkout. |
How it fits with other modules
- Shipping. Cross-border shipments
are normal Shipments with the
customsobject populated. - Carrier configuration. Cross-border defaults (incoterm, parties, smart defaults) are carrier-account configuration.
- Booking flow. Customs data is validated during the carrier booking call.
- Tracking. Once booked, cross-border shipments track the same way as domestic ones.