Home → Blog

You need an automated way to check congestion at the Port of Hamburg (DEHAM) so your transportation systems can adjust schedules, ETAs, and capacity plans. By the end of this guide, you will be able to query the FreightPulse API for DEHAM, parse the response in Python, and build a small wrapper that gracefully handles “no data” cases and the dataset’s ~6–7 day lag.

What this API provides (and what it does not)

The FreightPulse port congestion endpoint summarizes port activity levels from IMF PortWatch (UN Global Platform AIS data). Congestion here is a derived indicator: the last 7 days’ average port calls compared to a 90‑day baseline for the same port. This is refreshed daily but is not a live AIS feed, meaning data is lagged by ~6–7 days.

Illustration: API to Check Congestion at Hamburg

Use this signal to understand directional congestion pressure relative to recent history. It does not measure live anchorage or wait times for individual vessels and should not be conflated with real‑time queue length metrics. Avoid using it as a live ETA/berthing feed.

Authentication and request model

Authentication uses a simple header:

Every response is wrapped in a success/data envelope:

Endpoint for Hamburg (DEHAM): GET /api/v1/port-congestion?port=DEHAM.

Quick start: cURL for Hamburg

Run this cURL command to check DEHAM. It includes the required auth header and the exact query parameter for Hamburg:

curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=DEHAM"

Official sample JSON (copy/paste as-is for testing parsers):

{
    "success": true,
    "data": {
        "results": [
            {
                "port": "Hamburg",
                "locode": "DE HAM",
                "country": "Germany",
                "available": false,
                "reason": "No recent activity data for this port"
            }
        ],
        "global_summary": {
            "ports_high_congestion": 0,
            "ports_moderate": 0,
            "ports_low": 0
        },
        "meta": {
            "source": "IMF PortWatch (portwatch.imf.org) - UN Global Platform AIS data",
            "data_lag_days": "~6-7 (daily updates, not real-time)",
            "methodology": "congestion level is an approximation: last 7 days' avg port calls vs 90-day baseline for the same port. Does not measure vessel wait/anchorage time."
        }
    },
    "meta": {
        "request_id": "93610ae0-ba3c-4828-b3ac-5a8c5d724a6d"
    }
}

In this sample, available is false for Hamburg. Your integration must treat this as a valid response and fall back to alternative logic (e.g., default thresholds or deferring decisions until the next refresh). When Hamburg data is available, the same endpoint returns congestion metrics under the data/results array for the port.

Python: fetch and interpret Hamburg congestion

The snippet below calls the same endpoint, validates the envelope, and shows how to handle both “not available” and “available” shapes. When available, expect fields like congestion, ratio_vs_baseline, and as_of; when not available, check available and reason to decide your next step.

import os
import sys
import json
import time
from typing import Any, Dict, Optional

import requests

API_URL = "https://freightpulsehq.com/api/v1/port-congestion?port=DEHAM"
API_KEY = os.getenv("FREIGHTPULSE_API_KEY", "YOUR_API_KEY")

def fetch_deham_congestion(timeout: float = 10.0) -> Dict[str, Any]:
headers = {
"X-API-Key": API_KEY
}
resp = requests.get(API_URL, headers=headers, timeout=timeout)
resp.raise_for_status()
payload = resp.json()
if not isinstance(payload, dict) or "success" not in payload:
raise ValueError("Unexpected response format")
if payload.get("success") is not True:
raise RuntimeError(f"API returned success=false: {payload}")
return payload

def parse_hamburg_result(payload: Dict[str, Any]) -> Dict[str, Optional[Any]]:
data = payload.get("data", {})
results = data.get("results", [])
if not results:
return {
"available": None,
"reason": "Missing results array",
"congestion": None,
"ratio_vs_baseline": None,
"as_of": None
}
# Expect first result to be Hamburg
r0 = results[0]
available = r0.get("available")
if available is False:
return {
"available": False,
"reason": r0.get("reason", "Unavailable"),
"congestion": None,
"ratio_vs_baseline": None,
"as_of": None
}
# If available is True, read the core fields when present
# These fields are used by clients when the dataset is available:
# - congestion (categorical string, e.g., "low"|"moderate"|"high")
# - ratio_vs_baseline (float; 7-day avg vs 90-day baseline)
# - as_of (date or datetime string; last data point)
return {
"available": True,
"reason": None,
"congestion": r0.get("congestion"),
"ratio_vs_baseline": r0.get("ratio_vs_baseline"),
"as_of": r0.get("as_of")
}

def main() -> int:
try:
payload = fetch_deham_congestion()
parsed = parse_hamburg_result(payload)
print(json.dumps({
"hamburg": parsed,
"meta": payload.get("data", {}).get("meta", {}),
"request_id": payload.get("meta", {}).get("request_id")
}, indent=2))
return 0
except requests.HTTPError as e:
print(f"HTTP error: {e}", file=sys.stderr)
return 2
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1

if __name__ == "__main__":
raise SystemExit(main())

Notes for production use:

Interpreting congestion metrics for transportation workflows

When the dataset is available for DEHAM, you will see per-port fields commonly used by transportation teams:

Because this is not a live AIS wait-time metric, combine it with your own routing rules. For example, if ratio_vs_baseline is meaningfully above 1 for multiple consecutive updates, you might widen ETA buffers for Hamburg-bound legs and re-evaluate transshipment options upstream.

Caching, data lag, and update cadence

The congestion metric updates daily but reflects aggregated AIS observations that are lagged by ~6–7 days. Plan to cache a successful response for at least several hours (or a day) to avoid redundant polling while the source data is unchanged. For batch pipelines, schedule one daily pull shortly after your off-peak processing starts.

There is no pagination for a single-port query. If you later expand to multiple ports per run, combine sequential calls with short sleeps or concurrency controls to respect rate policies. The guest tier allows 100 requests/day per IP; for higher throughput, set X-API-Key with your key.

Field reference and envelope structure

At the top level, the API returns:

Within data:

When Hamburg data is available, expect these additional fields on the results item:

Practical integration tips specific to transportation systems

Error handling and resilience

Security and deployment

CLI and containerization tips

Linking this signal to routing and capacity planning

In routing rules, treat congestion and ratio_vs_baseline as context features alongside your internal KPIs (dwell times, terminal notices, rail handoff performance). If ratio_vs_baseline rises above a threshold for Hamburg over multiple daily snapshots, enlarge safety buffers on Hamburg-bound legs and preemptively allocate more slack or alternate transshipment nodes in your network model.

For capacity planning, integrate the ratio into your daily planning workbook or data warehouse. Join by port code (DEHAM) and date (as_of). Because the signal is relative to a 90‑day baseline, it naturally adapts to seasonal changes without requiring a custom normalization step.

Compliance notes

Registration and documentation

Get an API key and start testing against DEHAM:

FAQ

What if the response shows available: false for Hamburg?

Treat it as a valid response and follow your fallback path. Keep the last known value (if you have one) with an expiration time, or display “temporarily unavailable” in dashboards. Do not substitute zero or “low” congestion by default.

Is this a live AIS wait-time metric?

No. It’s derived from IMF PortWatch and is lagged by ~6–7 days. It compares 7‑day average port calls to a 90‑day baseline. It does not measure vessel wait or anchorage times.

What fields should my code read when data is available?

Read congestion (qualitative level), ratio_vs_baseline (numeric ratio), and as_of (effective date). Use the success/data envelope to guard your parsing logic.

Do I need to paginate or batch for a single-port request?

No pagination is needed for a single-port query. For multiple ports, call the endpoint per port and throttle to respect rate policies (guest is 100/day per IP).

How often should I refresh?

Once daily is typical, since updates are daily and lagged. Cache results between runs to avoid redundant calls.

Ready to integrate DEHAM congestion into your transportation workflows? Get your API key and deploy the Python snippet above into your scheduler today: Register. For field-level details and further endpoints, see the Documentation.