For each unique commodity in the shipment, create a CustomsItem object with description, quantity, weight, value, origin_country, and hs_tariff_number — use a separate CustomsItem per distinct HS code (UPS allows up to 100 items per customs declaration).
Create a CustomsInfo object that references all CustomsItem IDs, and set contents_type (e.g., merchandise), restriction_type, incoterm, and eel_pfc (Electronic Export License or exemption code for US exports).
Attach the CustomsInfo object to each Shipment leg that crosses an international border by including the customs_info field in the Shipment create payload.
Check the shipment's forms array after creation: EasyPost sets submitted_electronically: true if the carrier accepts electronic customs transmission, or includes a printable commercial invoice PDF that must be physically attached to the parcel.
For multi-leg routing where an intermediate leg is domestic, create a new Shipment object for each leg but re-use the same CustomsInfo object ID — CustomsInfo is immutable once created so correct all data before creation.
Validate that the declared value on CustomsInfo matches the commercial invoice to avoid customs holds caused by value discrepancies.
Known gotchas
CustomsInfo objects are immutable after creation — any error in HS codes, values, or country of origin requires creating an entirely new object; design a validation step before calling the create endpoint.
The eel_pfc field is required for US exports above certain value or technology thresholds under EAR; omitting it triggers carrier rejection even when EasyPost accepts the API call.
Some carriers apply per-leg customs requirements differently for transshipment hubs — verify with the carrier which legs require a full commercial invoice versus a transit declaration.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp