Skip to content

Extracting Delivery Terms (Incoterms) From a Purchase Order

9 min read · updated August 11, 2026

A delivery term is not free text. It is one of eleven codes from a published, dated vocabulary, followed by a place, and the two together decide who pays for carriage, who bears the risk, and who clears customs. Extracting the three letters alone extracts the least useful third of it.

The eleven rules

The Incoterms rules are published by the International Chamber of Commerce; the current revision, Incoterms 2020, entered into force on 1 January 2020. The US International Trade Administration’s summary of the 2020 rules lists them in two groups, and the grouping is the first validation you get for free.

Seven rules apply to any mode or modes of transport:

  • EXW — Ex Works
  • FCA — Free Carrier
  • CPT — Carriage Paid To
  • CIP — Carriage and Insurance Paid To
  • DAP — Delivered At Place
  • DPU — Delivered At Place Unloaded
  • DDP — Delivered Duty Paid

Four apply only to sea and inland waterway transport: FAS (Free Alongside Ship), FOB (Free On Board), CFR (Cost and Freight) and CIF (Cost, Insurance and Freight).

That split is a usable check. A term from the sea-only group on a shipment that is moving by air or road, or on containerised cargo handed over at an inland terminal, is a common commercial error rather than an extraction error — but your pipeline is the place it becomes visible. The ITA notes that DPU replaced the older DAT, with the added requirement that the seller unload the goods from the arriving means of transport.

The revision is part of the term

“FCA” on its own is ambiguous across revisions, and the revisions differ in ways that matter. DAT existed in Incoterms 2010 and does not exist in 2020; DDU existed in earlier revisions and was dropped; the insurance level required under CIP changed between revisions. Parties remain free to contract on an older revision if they name it, and plenty of long-running supply agreements do.

So the correct reading of a purchase order clause is the rule plus the revision the document names, and where the document names none, that fact is itself the extraction. Do not default the revision to the current one silently. Return null, record that the document did not state it, and let the contract or the supplier master supply it — a defaulted revision is an assumption that will be indistinguishable from a fact six months later.

A document reading “DAT Antwerp” is a genuinely interesting output: either it is an Incoterms 2010 term, in which case the revision is knowable, or somebody has used a retired code under a 2020 heading, which is worth a query. Returning null and recording why is the general pattern for handling a missing required field.

Incoterms revisions are periodic and the ICC has revised the rules roughly each decade. Everything above describes the 2020 revision as published at the time of writing; when a later revision is issued, the closed vocabulary this page relies on changes, and any validation list must be updated with it rather than assumed stable.

The named place is not optional

Each rule is followed by a named place, and the rule is close to meaningless without it. “FCA” says the seller delivers to a carrier; where that happens decides who pays for the leg before it. “FCA Seller’s Works, Stuttgart” and “FCA Port of Hamburg” allocate materially different costs.

The place also differs in kind between rules. For the C-group rules the named place is the destination to which the seller has contracted carriage, while the risk transfers earlier — which is the single most misunderstood point in the whole vocabulary, and a reason to keep the place as an extracted string rather than trying to infer where risk sits.

Practically, this means the extractor must return two fields and tolerate a messy second one. Places arrive as “Rotterdam”, as a UN/LOCODE such as NLRTM, as a full street address, as a plant code from the buyer’s own system, or as “buyer’s nominated warehouse”. Normalise where you can against your own location master; keep the raw string always.

Strings that are not Incoterms

A purchase order’s delivery-terms field attracts a lot of text that resembles an Incoterm and is not one. Matching a three-letter token without checking it against the closed set produces confident nonsense.

  • Retired codes. DAT and DDU are real terms from earlier revisions, not typos, and they should be extracted with the revision they belong to rather than corrected to a current code.
  • Informal abbreviations. C&F is trade shorthand for CFR and is not itself an Incoterm code. CNF appears for the same thing.
  • US domestic delivery terms. “FOB Origin” and “FOB Destination” are American domestic usage governed by commercial law rather than the ICC rules, and they mean something different from the ICC’s FOB — which applies only to sea and inland waterway carriage. On a US domestic PO, “FOB Destination” is almost certainly not an Incoterm at all. Extract it, flag the ambiguity, and do not map it onto the ICC vocabulary.
  • Carriage instructions. “Prepaid”, “Collect”, “Freight prepaid and add” describe who is billed for carriage. They frequently sit in the same field and they are not delivery terms.
  • Payment terms in the wrong box. CAD for cash against documents and COD for cash on delivery both look like three-letter codes and are neither Incoterms nor currencies — though CAD is also a currency code, which is exactly the kind of collision a closed-set check exists to catch.

Schema and validation

{
  "delivery_terms": {
    "rule": "DPU",                    // must be one of the 11
    "revision": "2020",               // null if the document does not state it
    "named_place": "Manchester, Trafford Park Depot",
    "named_place_code": "GBMNC",      // normalised, nullable
    "mode_class": "any_mode",         // derived: any_mode | sea_inland
    "as_printed": "DPU Manchester (Incoterms 2020)",
    "flags": ["revision_stated"]
  }
}

Four assertions do the work. The rule must be a member of the eleven for the stated revision, or of the set for the revision the document names. The named place must be present and non-empty; a rule with no place is incomplete and should be flagged rather than accepted. A sea-only rule on a shipment your own data says is moving by air or road is a flag. And as_printed must contain the extracted rule as a substring, which catches a model that produced a plausible code from context rather than from the page.

The reason to get this right is downstream: the term decides whether freight belongs on the supplier’s invoice at all, which is the check described in extracting freight and handling charges separately, and a change of term between PO revisions is a commercial change that must not be lost in a reprint diff, as in matching a purchase order to its amendments.