You need a reliable way to programmatically check port congestion for Kaohsiung (TWKHH) to drive transportation operations and schedules. By the end of this guide, you’ll be able to call a real HTTP endpoint, authenticate with an API key, parse the JSON envelope, and extract the congestion level, date, and ratio vs. baseline in Python.
What this API provides (and what it does not)
The FreightPulse port congestion endpoint returns a structured, lagged congestion signal for specific ports derived from IMF PortWatch. It is suitable for dashboards, alerts, and planning workflows where day-level updates suffice.
- Auth: header X-API-Key: YOUR_API_KEY. Guest access without a key is allowed at 100 requests/day per IP.
- Envelope: {"success": true, "data": { ... }} with nested result fields.
- Methodology: 7-day average vs. a 90-day baseline for the same port; this is not live AIS wait-time tracking.
- Update cadence: daily, with ~6–7 day lag; do not treat it as real-time.
- Scope for this post: Kaohsiung (TWKHH) only. Do not reuse the USLAX fixture for TWKHH.
- Do not quote a freight-rates USD fare as today’s price based on this endpoint; it is not a pricing feed.
Endpoint and parameters for Kaohsiung (TWKHH)
Use a GET request against this endpoint, specifying the port code TWKHH:
GET /api/v1/port-congestion?port=TWKHH
The header X-API-Key should carry your API key. If you do not have a key, you can still query as a guest within the daily limit. For production use and higher volume, register for an API key.
Copy-paste cURL you can run now
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=TWKHH"
Official JSON response example for Kaohsiung
{
"success": true,
"data": {
"results": [
{
"port": "Kaohsiung",
"locode": "TW KHH",
"country": "Taiwan Province of China",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 30,
"baseline_avg_portcalls_per_day": 27.7,
"ratio_vs_baseline": 1.08
}
}
],
"global_summary": {
"ports_high_congestion": 0,
"ports_moderate": 1,
"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": "d6b19527-8f54-4ddd-bd5e-069531828ecf"
}
}
Fields you will likely use in transportation workflows:
- congestion: a categorical label such as “low”, “moderate”, or “high”.
- as_of: the ISO date (YYYY-MM-DD) associated with the measurement window.
- metrics.ratio_vs_baseline: a numeric ratio of recent 7-day average port calls vs. the 90-day baseline; values above 1.0 indicate higher-than-baseline port call activity.
Python guide: calling the endpoint and parsing congestion for TWKHH
This walkthrough shows how to make a single request for Kaohsiung and safely extract congestion, as_of, and ratio_vs_baseline. It also includes simple checks for the JSON envelope and empty results.
Install and import
Use the built-in libraries and requests. If you don’t have requests:
python -m pip install requests
Code sample
import os
import requests
from typing import Optional, Tuple
API_URL = "https://freightpulsehq.com/api/v1/port-congestion"
PORT_CODE = "TWKHH"
def fetch_kaohsiung_congestion(api_key: Optional[str]) -> Tuple[Optional[str], Optional[str], Optional[float]]:
headers = {}
if api_key:
headers["X-API-Key"] = api_key
params = {"port": PORT_CODE}
resp = requests.get(API_URL, headers=headers, params=params, timeout=20)
resp.raise_for_status()
payload = resp.json()
# Basic envelope validation
if not isinstance(payload, dict) or not payload.get("success"):
raise RuntimeError("Unexpected API envelope or success=false")
data = payload.get("data", {})
results = data.get("results", [])
if not results:
# No data returned for this port
return None, None, None
# Assume the first result corresponds to the requested port
rec = results[0]
congestion = rec.get("congestion")
as_of = rec.get("as_of")
# metrics may be nested
metrics = rec.get("metrics", {})
ratio_vs_baseline = metrics.get("ratio_vs_baseline")
return congestion, as_of, ratio_vs_baseline
if __name__ == "__main__":
# Read from environment for convenience; falls back to guest if missing
api_key = os.environ.get("FREIGHTPULSE_API_KEY")
try:
congestion, as_of, ratio = fetch_kaohsiung_congestion(api_key)
if congestion is None:
print("No congestion record returned for TWKHH.")
else:
print(f"Kaohsiung (TWKHH) congestion: {congestion} as of {as_of} (ratio_vs_baseline={ratio})")
except Exception as e:
print(f"Error: {e}")
How to think about the signal for transportation use cases
The congestion category is a compact summary appropriate for routing decisions and stakeholder updates. The underlying ratio_vs_baseline is more granular and helps you set automated thresholds. For example, you could treat ratios above 1.1 as “elevated demand/throughput” and below 0.9 as “below baseline” when prioritizing port calls or scheduling inland drayage.
Important: the metric is about port call counts, not anchorage dwell or berth waiting times. It is most reliable for medium-horizon planning where daily updates suffice and finely grained intra-day AIS movements are not required.
Operational details that save time
- Units: recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day are counts of vessel port calls per day.
- Timestamps: as_of is a date string (YYYY-MM-DD) representing the effective date for the lagged signal; there is no time-of-day component.
- Update cadence and lag: the data is refreshed daily and typically lags by ~6–7 days. Do not build minute-by-minute alerts; schedule a daily pull off-peak and cache results.
- Caching: because of the lag, a 12–24 hour cache is usually safe. Invalidate when you see a new as_of date.
- Pagination: the endpoint, as used here, returns a focused set for the specified port; if you expand queries later, check the response for meta fields before implementing pagination logic.
- Error handling: test both guest and key-auth flows; handle success=false or empty results gracefully to avoid breaking dashboards.
- Guest access: without X-API-Key you are limited to 100 requests/day per IP. Add a key for production workloads or multi-user dashboards.
Common integration patterns for Kaohsiung (TWKHH)
- Daily ETL: run the cURL or Python job once per day, store congestion, as_of, and ratio_vs_baseline in a data warehouse table keyed by date and port code TWKHH.
- Threshold-based alerts: alert if ratio_vs_baseline crosses project-specific thresholds. Keep the current date and the as_of date in the message to avoid misinterpretation.
- Dashboard tiles: show the congestion label and ratio with a footnote stating “IMF PortWatch; lagged ~6–7 days.” Include the as_of date explicitly.
- Scenario toggling: compare the latest ratio_vs_baseline with your internal service level assumptions for berth windows, but do not treat it as actual queue length.
Testing and validation checklist
- Validate the JSON envelope: assert payload.success is true before parsing data.
- Confirm port identity: ensure results[0].locode includes “TW KHH” or that port equals “Kaohsiung.”
- Guard against nulls: metrics may be present but individual fields could be missing; set safe defaults.
- Surface the lag: display as_of in any UI element that shows congestion to prevent confusion with live AIS.
- Rate-limit hygiene: consolidate calls from multiple services into a single cached read per day to respect guest quotas, or provision a key.
Security, keys, and environments
Put the X-API-Key in a secure secret store and inject at runtime (e.g., environment variables). Rotate keys as part of your normal incident procedures. For local testing or simple prototypes, guest access can suffice, but moving to key-based auth is recommended for stability and observability.
Linking back to the official docs and registration
For endpoint details and any additional parameters, see the Documentation. To get a production API key, create an account here: Register.
FAQ
Is this data real-time AIS?
No. It is derived from IMF PortWatch and updates daily with a ~6–7 day lag. It should not be used as live anchorage or berth wait-time data.
Which fields should I store for automation?
Store congestion, as_of, and metrics.ratio_vs_baseline at a minimum. Optionally store recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day for auditability.
What happens if there are multiple results in data.results?
The query is for a single port, so typically you’ll get one primary record. If you extend usage later, handle arrays robustly and select by locode or port name as needed.
Can I use this to quote today’s freight rates?
No. This endpoint does not provide pricing and should not be used to quote a USD fare or rate.
How should I handle guest rate limits?
Cache the response for 12–24 hours and share it across services. If you need higher volume or multiple environments, use an API key via the X-API-Key header.
Next step
Set up a daily job that calls GET /api/v1/port-congestion?port=TWKHH, parse congestion, as_of, and ratio_vs_baseline, and expose it in your transportation dashboard with the lag disclaimer. When you’re ready for production keys and higher limits, create an account via Register, and consult the Documentation for any advanced options.