Skip to navigation

2. Create FTLs

Send each FTL once, then reuse its id

An FTL holds the cargo details: numbers, customer, consignee, containers, and the pickup and delivery days. You can create it in two ways:

Both ways apply the same validation and the same duplicate rule.

Request

curl -X POST "https://lastmile.milenow.com/index.php/api/v1/partners/shipments" \
-H "Authorization: Bearer $MILE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"shipment_no": "SHP-1001",
"bl_no": "BL-55001",
"created_on": "2026-11-03",
"expected_on": "2026-11-03",
"shipping_line": "MAERSK",
"payment_term": "Company Credit",
"shipping_charges": 2200,
"other_charges": 150,
"pickup_from_port": true,
"destination_port": "SA JED",
"customer": {
"name": "Coastal Trading LLC",
"phone": "+966500000000",
"address": "Al Sulaimaniyah Industrial, Jeddah"
},
"consignee": {
"name": "Coastal Trading Factory",
"address": "South Industrial Area, Jeddah"
},
"containers": [
{
"category": "Containers",
"product": "40ft GP Container - Full",
"container_no": "MSKU4821736",
"seal_no": "SL-77120",
"size": "40ft",
"quantity": 1,
"weight": 26000
}
]
}'

Required fields

FieldRule
shipment_no, bl_noYour FTL and bill of lading numbers
created_onPickup day, Y-m-d
expected_onDelivery day, Y-m-d. Same day as created_on or later
shipping_line, payment_termName or *_id from FTL options
shipping_charges, other_chargesNumbers, 0 or more
customerThe shipper. id, or name, phone and address for a new one
consigneeThe receiver. id, or name and address for a new one
containersAt least one. See below
vendorOnly when options returns vendor_required: true

Optional fields include vessel, voyage_no, tracking_no, notes, origination_port, stayed_ports, shipping_method, country and documents. The reference lists them all.

Customer and consignee

Send id to reuse a party: the consigner.id or consignee.id from an earlier FTL. For a new party, send name and address. A new customer also needs phone. Send the phone in the correct format for its country, with the country code. Mile matches it against existing customers in your account. Mile locates the address with Google Maps. Read customers and consignees for how phones and coordinates are matched.

Containers

FieldRule
category, productFrom categories[].products in options. Name or *_id
container_noUnique within the FTL. Alias container_id
seal_noAlias seal_number
size20ft, 40ft, 40ft HC or 45ft HC. 40HC, 40 hq and 20GP are also accepted
quantity1 to 10
weight0 or more

Pickup at a port

By default the container is picked up at the customer’s address. To pick it up at a port, send pickup_from_port: true and the port as destination_port (name, code or UN/LOCODE) or destination_port_id. Find ports with port search.

Documents

Optional. Each document has a type from options, a file_name ending in .png, .jpg, .jpeg or .pdf, and file_base64 of 300 KB or less.

Response

{
"status": 200,
"msg": "Shipment created",
"msgs": [],
"data": {
"id": 301,
"shipment_no": "SHP-1001",
"tracking_no": "TRK48210",
"bl_no": "BL-55001",
"status": { "id": 10, "name": "Awaiting Approval" },
"created_on": "2026-11-03 00:00:00",
"expected_on": "2026-11-03 00:00:00",
"consigner": { "id": 7001021045, "name": "Coastal Trading LLC", "address": "Al Sulaimaniyah Industrial, Jeddah", "latitude": 21.452, "longitude": 39.257 },
"consignee": { "id": 7001021046, "name": "Coastal Trading Factory", "address": "South Industrial Area, Jeddah", "latitude": 21.305, "longitude": 39.235 },
"pickup_from_port": true,
"destination_port": { "id": 61021, "name": "Jiddah", "unlocode": "SA JED" },
"containers": [
{ "id": 376, "container_no": "MSKU4821736", "seal_no": "SL-77120", "size": "40ft", "weight": "26000", "quantity": 1 }
]
}
}

The response is shortened here. Keep these fields:

  • id: send it as shipment_id in a trip stop.
  • consigner.id and consignee.id: send them as customer.id and consignee.id in later FTLs.

Errors

Every problem is in msgs. Fix them all and send again.

{
"status": 412,
"msg": "3 problems found, listed in msgs. Fix all of them and send again.",
"msgs": [
"expected_on (2026-11-01) is before created_on (2026-11-03). created_on is the pickup day and expected_on the delivery day",
"containers[0].product \"20ft\" matches more than one product, send the exact name: 20ft GP Container - Full, 20ft Container - Empty",
"containers[0].weight is required (0 or more)"
],
"data": []
}

The same shipment_no, bl_no and container number are already in your account. Use the shipment_id from the message instead of creating it again.

{
"status": 409,
"msg": "Shipment SHP-1001 with BL BL-55001 and container MSKU4821736 already exists as shipment_id 301. Use shipment_id 301 instead of creating it again.",
"msgs": ["Shipment SHP-1001 with BL BL-55001 and container MSKU4821736 already exists as shipment_id 301. Use shipment_id 301 instead of creating it again."],
"data": []
}

Next: build trips.