Guide · Python · SDK · REST API

UN/LOCODE Validation in Python — Ports & Trade Locations

Every port, airport, rail terminal, and inland clearance depot in international trade is identified by a UN/LOCODE — a five-character code maintained by the United Nations. Here's how the standard works, what each part of the code means, and how to validate and look up LOCODEs in your Python application.

1. What is a UN/LOCODE?

UN/LOCODE (United Nations Code for Trade and Transport Locations) is an international standard maintained by UNECE (United Nations Economic Commission for Europe). It assigns a unique five-character code to over 100,000 locations in more than 240 countries and territories.

The directory covers seaports, inland ports, airports, rail terminals, road terminals, postal exchange offices, multimodal facilities, border crossing points, and other locations relevant to international trade and transport. Each location receives a code regardless of its size — from the world's busiest container ports to small inland customs posts.

UN/LOCODEs appear throughout trade documentation: bills of lading, customs declarations, letters of credit, certificates of origin, dangerous goods manifests, and EDI messages such as EDIFACT and UN/CEFACT. Using the standardised code instead of free-text location names eliminates ambiguity — there is no confusion between "Warsaw", "Warszawa", and "Varsovie" when the code is simply PLWAW.

UNECE publishes updated directories twice a year, adding new locations and decommissioning codes that are no longer in active use. The registry is freely available but validation requires checking both format correctness and existence in the current directory.


2. LOCODE structure

A UN/LOCODE consists of exactly five characters, split into two parts:

PLWAW

Country Code

PL

2-letter ISO 3166-1 alpha-2

Location Code

WAW

3-character alphanumeric identifier

The first two characters are the ISO 3166-1 alpha-2 country code (e.g. PL for Poland, DE for Germany, US for the United States). The remaining three characters identify the specific location within that country. The location part can contain both letters and digits (A-Z, 2-9), though most codes use only letters.

Each location in the UN/LOCODE directory is tagged with one or more function classifiers indicating the type of facility available at that location:

CodeFunctionDescription
1PortSeaport or river port with vessel operations
2Rail terminalRail freight or passenger terminal
3Road terminalRoad freight terminal or truck depot
4AirportAirport with cargo or passenger operations
5Postal exchangePostal exchange office
6MultimodalFacility handling multiple transport modes
7Fixed transportFixed transport installation (pipeline, cableway)
BBorder crossingInternational border crossing point

Here are some well-known UN/LOCODEs:

LOCODELocationFunctions
PLWAWWarszawa, PolandRail, Road, Airport, Postal
DEHAMHamburg, GermanyPort, Rail, Road, Airport, Postal
USNYCNew York, United StatesPort, Rail, Road, Airport, Postal
CNSHAShanghai, ChinaPort, Rail, Road, Airport
SGSINSingaporePort, Rail, Road, Airport, Postal
NLRTMRotterdam, NetherlandsPort, Rail, Road, Airport, Postal
ℹ️The location code portion is not globally unique on its own — only the full five-character combination of country code + location code is unique. For example, "WAW" in isolation could theoretically appear in multiple countries.

3. Why LOCODE validation matters

Trade documentation accuracy

Bills of lading, commercial invoices, and packing lists reference ports of loading and discharge by their UN/LOCODE. An incorrect code can misdirect cargo, cause delays in customs processing, or trigger compliance alerts when the declared route does not match the physical movement of goods.

EDI and electronic messaging

EDIFACT messages (IFTMIN, COPARN, BAPLIE) and other electronic data interchange formats use UN/LOCODEs to identify origin, destination, and transshipment points. Invalid codes cause message rejection at the receiving system, breaking automated booking and planning workflows.

Customs automation

Modern customs systems (e.g. EU ICS2, US ACE) rely on UN/LOCODEs for automated risk assessment and routing decisions. Submitting an invalid or unknown LOCODE can result in declaration rejection, manual inspection queues, and fines for non-compliance.

Supply chain visibility

Freight visibility platforms map shipment milestones to geographic locations using UN/LOCODEs. Invalid codes create gaps in the tracking chain — a container may appear to vanish between two milestones because the intermediate location code was not recognised by the tracking system.


4. The right solution

The IsValid UN/LOCODE API provides two endpoints: a validate endpoint that checks a single LOCODE and returns its full metadata (name, subdivision, functions, IATA code, coordinates), and a list endpoint that returns all LOCODEs for a given country.

100,000+
Locations
from the UN/LOCODE directory
<20ms
Response time
fast lookup from indexed data
100/day
Free tier
no credit card

Validate endpoint

Check a single LOCODE, get location name, subdivision, transport functions, IATA code, and geographic coordinates.

List endpoint

Retrieve all LOCODEs for a specific country. Useful for building dropdowns, autocomplete inputs, and data migration scripts.

Full parameter reference and response schema: UN/LOCODE Validation API docs →


5. Python code example

Using the isvalid-sdk package or the requests library. Install with pip install isvalid-sdk or pip install requests.

Validate a single LOCODE:

# locode_validator.py
import os
from isvalid_sdk import IsValidConfig, create_client

iv = create_client(IsValidConfig(api_key=os.environ["ISVALID_API_KEY"]))

# ── Validate a UN/LOCODE ────────────────────────────────────────────────────

result = iv.locode("PLWAW")

if not result["found"]:
    print("LOCODE not found in the UN directory")
else:
    print(f"Name: {result['name']}")               # → 'Warszawa'
    print(f"Country: {result['country']}")           # → 'PL'
    print(f"Functions: {result['functions']}")       # → ['rail', 'road', 'airport', 'postal']
    print(f"IATA: {result['iata']}")                 # → 'WAW'
    print(f"Coordinates: {result['coordinates']}")   # → '5215N 02100E'

List all LOCODEs for a country:

# locode_list.py
import os
from isvalid_sdk import IsValidConfig, create_client

iv = create_client(IsValidConfig(api_key=os.environ["ISVALID_API_KEY"]))

# ── List LOCODEs for Poland ─────────────────────────────────────────────────

locations = iv.locode.list(country="PL")

print(f"Found {len(locations)} locations in Poland")

for loc in locations[:5]:
    funcs = ", ".join(loc["functions"])
    print(f"  {loc['locode']} — {loc['name']} ({funcs})")

In a shipment booking pipeline — validate origin and destination LOCODEs:

# Validate LOCODEs in a booking request
def validate_booking_locations(booking: dict) -> dict:
    origin = booking["origin"]
    destination = booking["destination"]

    origin_result = validate_locode(origin)
    dest_result = validate_locode(destination)

    errors = []

    if not origin_result["found"]:
        errors.append(f"Unknown origin LOCODE: {origin}")
    if not dest_result["found"]:
        errors.append(f"Unknown destination LOCODE: {destination}")

    if errors:
        return {"valid": False, "errors": errors}

    return {
        "valid": True,
        "origin": {
            "locode": origin_result["locode"],
            "name": origin_result["name"],
            "country": origin_result["country"],
            "functions": origin_result["functions"],
        },
        "destination": {
            "locode": dest_result["locode"],
            "name": dest_result["name"],
            "country": dest_result["country"],
            "functions": dest_result["functions"],
        },
    }
LOCODEs are case-insensitive. The API accepts both plwaw and PLWAW, but the canonical form returned in responses is always uppercase. Normalise user input to uppercase before storing.

6. cURL example

Validate a single UN/LOCODE:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/locode?value=PLWAW"

Validate a port LOCODE:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/locode?value=DEHAM"

List all LOCODEs for a country:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.isvalid.dev/v0/locode/list?country=PL"

7. Understanding the response

Validate endpoint — known LOCODE:

{
  "valid": true,
  "found": true,
  "locode": "PLWAW",
  "country": "PL",
  "location": "WAW",
  "name": "Warszawa",
  "nameAscii": "Warszawa",
  "subdivision": "14",
  "functions": ["rail", "road", "airport", "postal"],
  "iata": "WAW",
  "coordinates": "5215N 02100E"
}

Validate endpoint — unknown LOCODE:

{
  "valid": true,
  "found": false,
  "locode": "PLXYZ",
  "country": "PL",
  "location": "XYZ"
}
FieldTypeDescription
validbooleanWhether the LOCODE has a valid format (2-letter country + 3-char location)
foundbooleanWhether the LOCODE exists in the UN/LOCODE directory
locodestringThe normalised 5-character LOCODE (e.g. "PLWAW")
countrystringISO 3166-1 alpha-2 country code (e.g. "PL")
locationstring3-character location identifier (e.g. "WAW")
namestringLocation name, possibly with diacritics (e.g. "Warszawa")
nameAsciistringASCII-only transliteration of the location name
subdivisionstringISO 3166-2 subdivision code (e.g. "14" for Mazowieckie)
functionsstring[]Transport functions: port, rail, road, airport, postal, multimodal, fixed-transport, border-crossing
iatastringIATA airport code if applicable (e.g. "WAW")
coordinatesstringGeographic coordinates in UN/LOCODE format (e.g. "5215N 02100E")

List endpoint — response for a country:

[
  {
    "locode": "PLGDN",
    "country": "PL",
    "location": "GDN",
    "name": "Gdansk",
    "nameAscii": "Gdansk",
    "subdivision": "22",
    "functions": ["port", "rail", "road", "airport", "postal"],
    "iata": "GDN",
    "coordinates": "5423N 01840E"
  },
  {
    "locode": "PLWAW",
    "country": "PL",
    "location": "WAW",
    "name": "Warszawa",
    "nameAscii": "Warszawa",
    "subdivision": "14",
    "functions": ["rail", "road", "airport", "postal"],
    "iata": "WAW",
    "coordinates": "5215N 02100E"
  }
]
FieldTypeDescription
(root)arrayArray of LOCODE objects for the requested country
[].locodestringFull 5-character UN/LOCODE
[].namestringLocation name with diacritics
[].functionsstring[]Transport function classifiers for this location

8. Edge cases

Valid format but unknown location

A LOCODE can have a perfectly valid format (two-letter country code + three alphanumeric characters) but not exist in the UN/LOCODE directory. For example, PLXYZ has a valid format (PL is a valid country code, XYZ is a valid location pattern) but does not correspond to any registered location. The API distinguishes this with valid: true, found: false.

result = iv.locode("PLXYZ")
# result["valid"] is True   (format is correct)
# result["found"] is False  (not in the UN directory)

Decommissioned LOCODEs

UNECE periodically removes LOCODEs from the active directory when locations are merged, renamed, or no longer relevant for trade. A code that was valid in a previous edition of the directory may return found: false in the current version. If you are processing historical trade documents, be aware that the LOCODE may have been valid at the time of issuance but is no longer in the active registry.

LOCODE vs IATA codes

For locations with airports, the 3-character IATA airport code often matches the location portion of the UN/LOCODE. For example, Warsaw's IATA code is WAW and its UN/LOCODE is PLWAW — the location part is identical. However, this is not always the case. Some locations have different IATA and LOCODE identifiers, and many LOCODEs have no IATA code at all (e.g. inland customs posts, road terminals).

⚠️Do not assume that prepending a country code to an IATA code produces a valid UN/LOCODE. Always validate against the UN/LOCODE directory. The API response includes the iata field when an IATA code is associated with the location.

Summary

Validate both format and existence — a syntactically correct LOCODE may not be in the UN directory
Use the list endpoint to build country-specific dropdowns and autocomplete fields
Normalise LOCODEs to uppercase before storing — the canonical form is always uppercase
Check the functions array to verify the location supports the required transport mode
Do not assume IATA codes and LOCODE location parts are always identical
Do not rely on format validation alone — always check against the current UN/LOCODE directory

See also

Validate UN/LOCODEs instantly

Free tier includes 100 API calls per day. No credit card required. Validate and look up over 100,000 trade and transport locations from the UN/LOCODE directory.