AI document processing for freight forwarders: bills of lading, invoices and the customs sign-off
A Dubai forwarder's AI project that pays for itself: read the document pack into structured records, flag what does not reconcile, and keep the customs declaration with a licensed human. Here is how to scope it, what it costs per page, and what accuracy to demand before you go live. Freight forward
Posted on Oct 28 • Originally published at azrty.com
A Dubai forwarder's AI project that pays for itself: read the document pack into structured records, flag what does not reconcile, and keep the customs declaration with a licensed human. Here is how to scope it, what it costs per page, and what accuracy to demand before you go live.
Freight forwarding in the Gulf is document work wearing a logistics badge. Every consignment arrives as a pack: commercial invoice, packing list, bill of lading or air waybill, certificate of origin, delivery order, and finally a WhatsApp photo of the signed delivery note. Someone re-types the fields your systems need; a licensed person files the customs declaration.
Reading that pack into structured data is the clearest AI return a forwarder can get this year: it removes typing hours per consignment, catches mismatches before they reach customs, and leaves the legally sensitive step with a person. Vendors are pitching exactly this across Dubai in 2026, from document automation to WhatsApp status bots ( Soluvide, Runbook). This piece covers the pipeline, the engines and their published per-page prices, the accuracy bar to demand before go-live, how "where is my shipment" gets answered from live data, and a scope you can hand straight to an IT partner.
"Reading" a shipping document is three steps, and the second one is where the money is:
Extraction alone only moves errors faster. Extraction plus validation catches the mismatched container number before it reaches the declaration, which is where the cost lives: a wrong identifier in a customs filing means amendment fees, delay, and often storage or demurrage on top. The DCSA makes the same point about the bill of lading: it is the most important trade document in container shipping, and its electronic B/L standard exists so B/L data flows straight through without manual re-entry.
The boundary is fixed, and vendors who claim otherwise deserve caution. AI prepares and checks data. A licensed person submits the customs declaration and carries the declarant's responsibility, through the relevant system, whether that is Dubai Customs' Mirsal 2 or the equivalents in other emirates and in Saudi Arabia. Check the current guidance from the authority you file with ( Dubai Customs ). The same rule covers anything with legal weight: issuing the B/L as a carrier, approving invoices and credit notes, committing to delivery dates your data does not support, and signing anything.
The build that works has four stages, and it is mostly unglamorous code:
The schema is where you decide what a "field" means. A short Pydantic model for the invoice side of the pack:
from typing import Annotated, Literal from pydantic import BaseModel, Field, StringConstraints ContainerNumber = Annotated [ str, StringConstraints ( pattern = r " ^[A-Z]{4}\d{7}$ " )] class LineItem ( BaseModel ): description: str hs_code: str | None = None # suggestion only, never final quantity: float | None = None unit: str | None = None net_weight_kg: float | None = None gross_weight_kg: float | None = None unit_value: float | None = None currency: Literal [ " AED ", " USD ", " EUR ", " GBP ", " CNY ", "" ] | None = None class ShipmentPack ( BaseModel ): document_type: Literal [ " bl ", " invoice ", " packing_list ", " coo ", " delivery_order ", " other " ] bl_number: str | None = None container_numbers: list [ ContainerNumber ] = Field ( default_factory = list ) incoterm: str | None = None # closed list, checked downstream consignee_name: str | None = None lines: list [ LineItem ] flags: list [ str ] = Field ( default_factory = list ) Enter fullscreen mode Exit fullscreen mode Then the checks the model never gets to vote on. Container numbers carry an ISO 6346 check digit, so a wrong digit is provable in ten lines of Python:
def iso_6346_valid ( container: str ) -> bool: if len ( container )!= 11: return False vals, v = {}, 10 for ch in " ABCDEFGHIJKLMNOPQRSTUVWXYZ ": if v % 11 == 0: # 11, 22 and 33 are skipped by the standard v += 1 vals [ ch ] = v v += 1 body = container [: 10 ] total = sum ( vals [ c ] * ( 2 ** i ) if c. isalpha () else int ( c ) * ( 2 ** i ) for i, c in enumerate ( body ) ) expected = " 0 " if total % 11 == 10 else str ( total % 11 ) return container [ 10 ] == expected Enter fullscreen mode Exit fullscreen mode Beyond format checks, cross-document rules do the real work: container numbers must agree across the B/L, packing list and delivery order; parties must match the customer record; line values times quantities must recompute; gross weight must be at least net weight; the B/L date must precede arrival; incoterms must come from the 2020 set and currencies from ISO 4217. Any miss raises a named flag on the pack, and the pack stops.
OCR is a commodity. The interesting choice is what turns OCR text into fields. Four viable patterns, at the list prices published on each vendor's pricing page (check them, they move):
The usual right answer for a forwarder is the first row. Document AI and Textract both charge pennies for raw OCR ($1.50 per 1,000 pages for Google's Enterprise Document OCR, $0.0015 per page for Textract's Detect Document Text), and a hosted LLM handles the messy part: carrier-specific B/L layouts, stamps over printed fields, mixed Arabic and English. The specialised parsers are cheaper per page but tuned for invoices, so you end up running them alongside something else anyway. If consignee data cannot leave your estate, run open-weights vision models on your own GPUs and pay in operations instead of per page.
One pattern worth copying: run the system inside your own cloud account, under your name, and go live only after it passes a test set built from your hardest real consignments and frozen before the build starts.
A mid-sized Dubai forwarder clearing imports through Jebel Ali and Dubai South. Assumptions: 2,500 consignments a month, an average pack of 10 pages, so 25,000 pages a month (300,000 a year), arriving as a mix of clean PDFs, scans and WhatsApp photos.
Model spend. OCR on Google Enterprise Document OCR at $1.50 per 1,000 pages: 25 x $1.50 = $37.50 a month. LLM extraction: roughly 2,000 input tokens per page (OCR text plus schema and instructions) and 800 output tokens, so 50M input and 20M output tokens a month. At $3 per million input and $15 per million output, a typical mid-tier hosted model price: $150 in, $300 out, $450 a month. Total model spend about $490 a month (AED 1,800), under $0.02 per page. The same volume on Textract Forms plus Tables ($0.05 plus $0.015 per page) would be $1,625 a month; the specialised expense parser ($0.01 per page) $250.
Current manual cost. Assume the documentation team spends 12 minutes re-typing and checking each pack: 30,000 minutes, about 500 hours, roughly 3 full-time people. At AED 9,000 a month fully loaded per documentation officer, AED 27,000 a month (about $7,350).
After go-live. Expect 60 to 70 per cent of packs to pass clean if the mix is mostly clean PDFs, fewer if WhatsApp photos dominate; take 60 per cent straight through. The other 40 per cent, 1,000 packs, need about 4 minutes each in the review UI: about 67 hours, 0.4 of an FTE, AED 3,600 a month. Post-go-live total: about AED 5,400 a month (models plus a part-time reviewer) against AED 27,000. The saving is roughly AED 21,600 a month (about $5,900), before you count faster quotes or the wrong-container incidents that never happened. A build costing six figures of dirhams pays back inside a year at those numbers. The review queue never disappears; it gets much shorter.
Vendors quote "95 per cent accuracy", which means nothing without definitions. Demand these instead:
Three definitions make those numbers real:
The gate to set before go-live: zero silent identifier errors across two consecutive golden-set runs, and a straight-through touch rate that has stopped improving week on week. Pin model versions, log every approval (who, when, which model version, which prompt), and keep a human sign-off screen between the extracted record and anything that touches customs, a bank or a customer's money.
The status question is not a document problem, it is a data problem, and the model's job in it is small. The answer lives in your TMS or freight system and in carrier feeds; the assistant only turns the question into a lookup and the record into a reply. The design that works:
{ "name": "shipment_status", "description": "Return verifiable milestones for one shipment owned by the verified customer.", "parameters": { "type": "object", "properties": { "reference": { "type": "string", "description": "BL, booking or PO number" } }, "required": [ "reference" ] } } Enter fullscreen mode Exit fullscreen mode Proactive updates through templates. Milestone messages go out as approved WhatsApp templates on your Business API number. Meta's template rules and the customer service window change, so check the current policy when you scope rather than trusting a vendor's screenshot.
The prerequisite is honest: a status bot is only as current as your shipment events. If milestones live in a shared drive and a WhatsApp group, wiring the bot to live data is the actual project, and the document pipeline above is what fills that data in the first place.
Three rules keep this build safe in the UAE.
Personal data applies to shipping documents. Consignee names, addresses and phone numbers are personal data, and Federal Decree-Law No. 45 of 2021 (the PDPL, effective 2 January 2022) covers controllers and processors in the UAE and anyone processing the data of subjects inside the State. It imposes purpose limitation, accuracy, security measures and retention limits, and it leaves free zones with their own regimes, such as DIFC and ADGM, so confirm which regime applies to your licence before you pick a model API. Sending consignee records to an overseas model endpoint is a cross-border transfer: prefer in-region endpoints or self-hosted models, and paper the data processing terms before the first page is read.
The declarant stays liable. AI can draft the declaration and check the pack against the documents, but submission and the declarant's responsibility stay with your licensed staff. Put that in writing in the design, and make the sign-off screen impossible to bypass.
Standards pay twice. Align your internal shipment record with the DCSA electronic B/L standard (open APIs for straight-through B/L data, aligned with IMO, ISO and UN/CEFACT). Carrier eBL data then flows into the same record your document pipeline fills, and you enter it once instead of three times.
Copy this, fill the brackets, and you have a pilot scope an engineering team can quote against:
AI document processing for freight forwarding: pilot scope 1. Volume: [N] consignments/month, [M] pages/month, channels: email, portal, WhatsApp. 2.
Document types: B/L, air waybill, commercial invoice, packing list, certificate of origin, delivery order, declaration draft. 3. Fields: [list per document type; ~40 on the invoice].
4. Extraction: OCR + LLM structured output; schema versioned; model versions pinned. 5.
Validation: ISO 6346 check, cross-document container and party match, totals recomputed, incoterm/currency/country closed lists, date sanity. 6. Exceptions: named flags; queue UI with source page beside extracted value; SLA hours.
7. Outputs: shipment record into [TMS/FMS]; declaration draft, never submitted; API/CSV. 8.
WhatsApp: status lookup on [number]; identity via [CRM]; template list; human hand-off rules. 9. Compliance: PDPL review; data residency [UAE or self-hosted]; retention [X] months; DPAs signed.
10. Acceptance: golden set of 300+ documents frozen before build; gates per field class; zero silent identifier errors in two consecutive runs; licensed person submits every filing. Enter fullscreen mode Exit fullscreen mode What to do next Pull 300 real documents across your channels and freeze the golden set.
Define your field lists and validation rules. Pick the engine and the data residency. Pilot one lane with the review queue running in parallel with manual entry.
Only then widen the funnel and switch on the WhatsApp status replies. Time spent at the front on the golden set and the rules buys a pipeline your documentation team will actually thank you for, and a customs sign-off that never once left human hands.
If you want the review queue and the integration built around your own systems rather than bolted onto a vendor's, that is our kind of work: Azrty builds AI engineering projects on your infrastructure and connects them to your systems, from our team in Dubai, with your developers able to extend what we leave behind. Where several model providers are in play, one gateway in front of them ( FastLLM Proxy ) keeps routing, budgets and access control in one place instead of scattered across services.