Air Waybill OCR: Read MAWBs and HAWBs into Checked Shipment Data
← All posts
GuideOct 21, 2026· 9 min read

Air Waybill OCR: Read MAWBs and HAWBs into Checked Shipment Data

If you searched for air waybill OCR, you probably have master and house air waybills arriving as PDFs, scans from an overseas agent, or photos of the copy that traveled with the cargo, and someone on the desk retypes the AWB number, airports, pieces, weights, and charges into the forwarding or customs system. Short answer: OCR is the right tool for the air waybills that reach you only as paper or images. Run each page through Markdown OCR so the numbered boxes and the rating table are searchable, validate the 11-digit AWB number with its check digit, test the rate line arithmetic in your own code, and reconcile every house air waybill against its master before anything updates a booking. When the airline or your own system already holds the shipment as an electronic message, use the message.

This post covers the air waybill as its own document class. For the whole forwarder packet of invoices, packing lists, bills of lading, and AWBs in one pipeline, read freight forwarding OCR. For ocean transport documents, read bill of lading OCR. For the declaration the broker files once the goods land, read OCR for customs declarations.

What an air waybill is, and why it is not a bill of lading

The air waybill is the contract of carriage between the shipper and the airline. IATA’s e-AWB handling guideline notes that the paper form is governed by IATA Resolution 600a, with the conditions of contract printed on the reverse under Resolution 600b. The US International Trade Administration adds the detail that matters most for document handling: air waybills are shipper-specific and not negotiable, unlike the order bills of lading used for vessel shipments. Nobody takes delivery by presenting an original AWB, so your pipeline is about data, not title.

Two layers show up on most forwarded shipments:

Document Who issues it What OCR must not confuse
Master air waybill (MAWB) Airline, or a forwarder on the airline’s stock The 11-digit AWB number, airline routing, total pieces and weight for the whole consolidation
House air waybill (HAWB) Forwarder to the actual shipper Forwarder’s own house number format, real shipper and consignee, pieces and weight for one shipment

Keep the master number and the house number in separate fields. A house number usually follows the forwarder’s own scheme and will not pass the airline check digit, which is expected, not an error.

First check whether you need OCR at all

A large share of air cargo now moves without a paper AWB. IATA describes the Multilateral e-AWB Agreement (Resolution 672) as removing the requirement for a paper air waybill between participating airlines and forwarders. Under e-AWB, the forwarder transmits the master data as an FWB message (or its Cargo-XML equivalent) and house data in FHL messages for consolidations, as the e-AWB guideline above describes.

That leaves OCR a clear but narrower job:

  • Inbound copies from agents who send you a scanned house or master AWB instead of message data
  • Lanes and partners not on e-AWB, where paper still travels in the pouch
  • Archives of AWBs from before your system captured message data, often needed for claims, audits, or duty refund work
  • Copies printed for customs or tax purposes, which the e-AWB guidelines still allow when local rules require paper

If you can read the FWB or FHL from your own system or the airline, do that. OCR is for the pages that never became data on your side.

Which AWB fields to extract

An air waybill packs a lot into labeled boxes. The values most desks actually need fall into a few groups:

  • Identity: AWB number (three-digit airline prefix, seven-digit serial, one check digit), house number on a HAWB, issue date and place
  • Parties: shipper, consignee, issuing carrier’s agent, and the notify or also-notify party when printed
  • Route: airport of departure, routing and destination with carrier codes, requested flight and date when present
  • Charges declaration: currency, prepaid or collect, declared value for carriage (often NVD, no value declared), declared value for customs (often NCV, no customs value), amount of insurance
  • Rating table: number of pieces, gross weight with K or L for kilograms or pounds, rate class, chargeable weight, rate or charge, and line total
  • Handling information: special handling codes, temperature instructions, and references to documents in the pouch
  • Goods description: nature and quantity of goods, dimensions or volume, and on a master for a consolidation, usually a pointer to the attached house manifest rather than a real description

The e-AWB guideline lays out the electronic version of the rating line as pieces, weight code, gross weight, rate class code (C, M, N, or Q), commodity item number, chargeable weight, rate, and total charge. That is a useful map for the printed table too, because the same values sit in the same order on most AWB forms.

Read the AWB into Markdown first

OCRskill exposes two outputs on the same Bearer-token auth. POST /ocr returns Markdown for any page. POST /ocr.json returns typed JSON for fields you list. Both accept images (PNG, JPEG, WebP, GIF, BMP, TIFF) and documents including PDF, Word, Excel, and CSV, up to 20 MB per request. A free key from get-key.json is enough to test.

Start every AWB with Markdown:

curl https://api.ocrskill.com/get-key.json

export API_KEY="sk-your-key-here"

curl https://api.ocrskill.com/ocr \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@mawb-016-12345675.pdf" > mawb.md

On a clean scan you usually get the box labels next to their values and the rating section as a table, sometimes as an HTML <table> inside the Markdown. Keep that file beside the original so a clerk can search the AWB number or a handling code without reopening the image.

Typed JSON helps less here than on an invoice. The documented catalog has no awb_number, chargeable_weight, or airport_of_departure field, and unknown field names return 400, so do not invent them. The invoice-style seller_name and buyer_name fields can give a rough hint for shipper and consignee when the layout prints clear names. Mark them optional with a trailing ? so one smudged box does not reject the request:

curl "https://api.ocrskill.com/ocr.json?fields=seller_name?,buyer_name?" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@hawb-scan.pdf"

Treat those values as hints and confirm them against the Markdown labels, because “seller” and “shipper” are not the same role on every shipment. The structured OCR JSON API post explains required versus optional fields and the 400 response that carries the extracted text for review.

Check the AWB number and the rate line in code

Two checks catch most of the mistakes that hurt on air waybills.

The AWB number. The Australian Border Force air waybill validation note describes the number as the issuing carrier’s three-digit IATA airline code, a seven-digit serial, and a check digit equal to the remainder of the serial divided by 7. A single misread digit in the serial almost always breaks that remainder.

The rate line. Chargeable weight should never be lower than the gross weight on the same line, because it is the higher of actual and volumetric weight, or a higher weight break the forwarder chose for a better rate. For most rate classes, rate times chargeable weight should equal the line total. The minimum charge class M is the exception, since it bills a flat amount.

This sketch scans OCR Markdown for AWB numbers and for rating rows laid out as pipe-delimited table rows in the order pieces, gross weight, weight code, rate class, chargeable weight, rate, total:

import re
import sys

AWB_RE = re.compile(r"\b(\d{3})[-\s]?(\d{7})(\d)\b")
# pieces | gross weight | K/L | rate class | chargeable weight | rate | total
RATE_RE = re.compile(
    r"\|\s*(\d+)\s*\|\s*([\d.,]+)\s*\|\s*([KL])\s*\|\s*([MNQC])\s*\|"
    r"\s*([\d.,]+)\s*\|\s*([\d.,]+)\s*\|\s*([\d.,]+)\s*\|"
)


def num(value: str) -> float:
    return float(value.replace(",", ""))


def awb_ok(serial: str, check: str) -> bool:
    return int(serial) % 7 == int(check)


def check_rate_line(m: re.Match) -> list[str]:
    pieces, gross, unit, rate_class, chargeable, rate, total = m.groups()
    gross, chargeable = num(gross), num(chargeable)
    rate, total = num(rate), num(total)
    issues = []
    if chargeable < gross:
        issues.append(f"chargeable weight {chargeable} is below gross {gross}")
    if rate_class != "M" and abs(rate * chargeable - total) > 0.05:
        issues.append(
            f"rate {rate} x chargeable {chargeable} = {rate * chargeable:.2f}, "
            f"but total reads {total}"
        )
    return issues


def check(markdown: str) -> dict:
    awbs = [
        {"value": f"{m.group(1)}-{m.group(2)}{m.group(3)}",
         "valid": awb_ok(m.group(2), m.group(3))}
        for m in AWB_RE.finditer(markdown)
    ]
    rate_lines = [
        {"line": m.group(0).strip(), "issues": check_rate_line(m)}
        for m in RATE_RE.finditer(markdown)
    ]
    return {"awbs": awbs, "rate_lines": rate_lines}


if __name__ == "__main__":
    print(check(open(sys.argv[1], encoding="utf-8").read()))

Run it with python3 check_awb.py mawb.md. On a test file containing 016-12345675, the row | 4 | 210.0 | K | Q | 260.0 | 3.10 | 806.00 |, and the row | 2 | 95.5 | K | N | 90.0 | 4.20 | 401.10 |, the AWB passes, the first row is clean, and the second row reports both a chargeable weight below gross and a total that does not match the rate.

Adjust the table regex to the column order your carriers actually print, and expect to add a second pattern for forms that put the commodity item number in its own column. Like any 11-digit pattern, AWB_RE can also match phone or account numbers, so only trust hits near an AWB label. A valid check digit proves the number is well formed, not that it belongs to this shipment.

Reconcile house air waybills against the master

A single clean page is not the finish line on a consolidation. Before you push data anywhere, compare the layers:

  1. Same master number. Every HAWB in the file should reference the MAWB number you extracted. A house that points to a different master is a hard review item.
  2. Pieces and weight add up. The sum of house pieces and gross weights should match the master totals, within whatever rounding your carriers use. Chargeable weights usually do not add up neatly, because each house is rated on its own.
  3. Compatible airports. House origin and destination should be consistent with the master routing, allowing for documented trucking legs.
  4. Party roles. The master shipper and consignee are often the two forwarder offices. The real cargo owner sits on the house. Do not overwrite booking parties from the wrong layer.
  5. Charges direction. Prepaid on the master and collect on a house is normal. Prepaid versus collect contradictions inside one document are worth a look.

Wire those checks in code with exact matches for numbers and fuzzy matching for party names, and keep the original scan one click away from every flagged item.

A practical pipeline for the air desk

  1. Capture. Drop agent PDFs, pouch scans, and portal downloads into a staging folder keyed by job or MAWB number. Keep the original bytes and a content hash.
  2. Classify. Tag MAWB, HAWB, house manifest, or “not an AWB” before extraction. Split packets that also carry the commercial invoice or packing list.
  3. Markdown OCR. Run /ocr on every AWB page and store the Markdown next to the original.
  4. Validate. Check AWB numbers, rate lines, and house versus master totals. Anything that fails goes to review.
  5. Hand off. Push only validated values into the forwarding or customs system, with links back to the scan and Markdown.

For larger volumes, a paid key can use a document URL so OCRskill fetches files already in your storage, and an OCR callback that returns 202 and posts the result to your endpoint later. Free keys get 403 for both.

Limitations to plan for

  • No AWB field catalog. Typed extraction covers invoice-style parties, not AWB numbers, airports, or rating fields. Markdown plus your own parsers is the real product.
  • Dense, small print. AWB boxes are tiny, and carbon or thermal copies fade. Expect more review on those pages, and scan at a resolution where the rating table is legible to a person.
  • Layout drift. Airline and neutral AWB forms share a structure, but column widths, merged cells, and handwritten amendments vary. Test your table parser on every major carrier you handle.
  • Divisors and rating rules. Volumetric weight is often computed with a divisor of 6,000 cubic centimeters per kilogram for general cargo, but carriers and express services can use different values, and the carrier’s tariff governs. Do not hard-code one divisor as a rule your checker enforces.
  • Decisions stay with people. OCR finds and checks the values. Release instructions, dangerous goods acceptance, and customs filings stay with trained staff and your systems of record.

Before you trust the pipeline, take fifty real MAWB and HAWB sets from last quarter, run them through, and count how often a clerk still corrects an AWB number, a weight, or a party. That correction rate tells you which agents and carriers are ready for light review and which still need a person on every page.

Conclusion

Air waybill OCR is worth doing for the paper and PDFs that never became message data on your side, and for nothing else. The work that pays off is small and checkable: Markdown for every page, the modulus 7 check on every AWB number, arithmetic on every rate line, and house totals matched against the master. Those checks turn a hard-to-read form into a short review list. Start with one airline and one agent, measure how often people still correct the output, and widen from there.

To try it, get a key from get-key.json, run a recent master air waybill through /ocr, and feed the Markdown into the checker above. Product details and pricing are at ocrskill.com.