You need a reliable way to check current congestion signals for container activity at Shekou (Shenzhen) so you can plan transport schedules and communicate ETAs without scraping AIS or guessing from anecdotal reports. By the end of this guide, you will be able to call a single HTTP endpoint for Shekou, parse congestion fields in Python, and integrate the result into your transportation dashboards and alerting.
What this endpoint provides (and what it does not)
The congestion endpoint returns a simple, consistent envelope with a congestion label and a few metrics for Shekou (Shenzhen). The data source is IMF PortWatch (UN Global Platform AIS), updated daily but lagged by roughly 6–7 days. This measures the last 7 days’ average port calls relative to a 90-day baseline; it does not measure anchorage wait times or live queue length from AIS.
Expect the standard envelope format: {"success":true,"data":{...}} with a results array containing the port entry you requested, plus a global summary and a methodology block. Key fields you will use:
- congestion: qualitative level such as low, moderate, high.
- metrics.ratio_vs_baseline: numeric ratio comparing the recent 7-day average to the 90-day baseline (unitless).
- as_of: date string (YYYY-MM-DD) indicating the observation date for the computed averages.
Important constraints:
- Port congestion is IMF PortWatch, lagged ~6–7 days, 7-day average vs 90-day baseline — not live AIS.
- Do not quote a freight-rates USD fare as today’s price; this endpoint is not a freight rates feed.
Authentication and access
Authentication is via a header: X-API-Key: YOUR_API_KEY. If you do not supply a key, you are treated as a guest with 100 requests per day per IP. For sustained polling or production workloads, use your own key to avoid shared-IP throttling.
Copy these values exactly as shown; never paste a real key into public code repositories. Keep your key in an environment variable or a secrets manager in production deployments.
Quick test with curl
Run this from any shell with curl installed. It queries Shekou (Shenzhen) directly and returns the full JSON envelope.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=Shekou"
Official example JSON response
Below is an official sample. Field names and structure will match what your integration should parse. The sample is based on IMF PortWatch and is lagged (~6–7 days), meaning it is not real-time AIS.
{
"success": true,
"data": {
"results": [
{
"port": "Shekou (Shenzhen)",
"locode": null,
"country": "China",
"congestion": "moderate",
"as_of": "2026-10-09",
"metrics": {
"recent_avg_portcalls_per_day": 8.4,
"baseline_avg_portcalls_per_day": 8.2,
"ratio_vs_baseline": 1.02
}
}
],
"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": "13a8c30d-bff9-4876-a6a6-4dbde7ed4397"
}
}
Fields to extract in your app:
- data.results[0].congestion for the qualitative label.
- data.results[0].metrics.ratio_vs_baseline to quantify directionality relative to historical baseline.
- data.results[0].as_of for the observation date (YYYY-MM-DD, UTC context).
Python integration: fetch and parse congestion for Shekou
The following Python snippet calls the same endpoint, handles the envelope, and prints a concise status line that you can pipe into logs or an alert. It also includes basic timeout handling and checks for the results array.
Python code
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 = "Shekou"
API_KEY = os.environ.get("FREIGHTPULSE_API_KEY", "YOUR_API_KEY")
def get_shekou_congestion(session: Optional[requests.Session] = None, timeout: float = 10.0) -> Dict[str, Any]:
sess = session or requests.Session()
headers = {
"X-API-Key": API_KEY
}
params = {
"port": PORT
}
resp = sess.get(API_URL, headers=headers, params=params, timeout=timeout)
resp.raise_for_status()
payload = resp.json()
if not isinstance(payload, dict) or not payload.get("success") or "data" not in payload:
raise ValueError("Unexpected response envelope")
data = payload["data"]
results = data.get("results") or []
if not results:
raise ValueError("No results for requested port")
result = results[0]
return {
"port": result.get("port"),
"country": result.get("country"),
"as_of": result.get("as_of"),
"congestion": result.get("congestion"),
"ratio_vs_baseline": (result.get("metrics") or {}).get("ratio_vs_baseline")
}
def main():
try:
info = get_shekou_congestion()
port = info.get("port")
as_of = info.get("as_of")
label = info.get("congestion")
ratio = info.get("ratio_vs_baseline")
# Example: emit a single line for logging/alerts
print(f"{port} congestion={label}, ratio_vs_baseline={ratio}, as_of={as_of}")
except requests.HTTPError as e:
print(f"HTTP error: {e}", file=sys.stderr)
sys.exit(1)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(2)
if __name__ == "__main__":
main()
Notes:
- Keep your key in FREIGHTPULSE_API_KEY; the code falls back to YOUR_API_KEY for local tests.
- Use a Session for connection reuse in daemons or serverless warm containers.
- Handle empty results explicitly in case the port name is misspelled or unsupported.
Operational details that save time
Update cadence and lag: data is updated daily but reflects a ~6–7 day delay from real time. Do not use it for live anchorage or berth-wait monitoring; it is a rolling 7-day average of port calls benchmarked to a 90-day history.
Timestamps: as_of is a date (YYYY-MM-DD). Treat it as UTC. Avoid converting to local time since it is a daily aggregate date, not a timestamp.
Units: ratio_vs_baseline is unitless (e.g., 1.02 means 2% above baseline). recent_avg_portcalls_per_day and baseline_avg_portcalls_per_day are counts per day.
Caching: because the series is updated daily with a 6–7 day lag, poll at most once per day per port in production and cache the response. For staging or demos, 1–4 hour caches keep the UI responsive without needless hits. Respect guest daily limits if you are not using a key.
Error handling: check HTTP status and the success boolean. If success is false or the results array is empty, back off and surface a clear error. Network errors should be retried with exponential backoff.
Pagination: this endpoint returns a results array for the requested port and does not require pagination for a single-port query.
Building a minimal service or CLI
For dashboards, provide a small service endpoint that reads the JSON, extracts congestion, ratio_vs_baseline, and as_of, and stores it in your metrics database with a daily TTL. Schedule it after your daily ETL cutover so cache and charts update predictably.
For alerting, set your threshold rules on ratio_vs_baseline (e.g., above 1.10 or below 0.90) and include the congestion label to keep notifications readable. Because the metric is lagged, avoid on-call paging; route alerts to planning channels instead.
Input parameters and port naming
Use port=Shekou for Shekou (Shenzhen). The returned object will clarify the port field as Shekou (Shenzhen) and country as China. If you manage a list of Chinese South China Sea gateways, key your configuration by this exact request parameter to avoid drift.
If you expand later to nearby terminals or sister ports, keep a mapping layer; but for this guide, stick to Shekou to avoid mixing signals.
Common pitfalls and how to avoid them
- Treating the data as live AIS: it is not live. It is a lagged, aggregated signal from IMF PortWatch.
- Overpolling: daily is sufficient. Cache results; do not call this endpoint every minute.
- Ignoring the envelope: always check success and drill into data.results[0].
- Using the value for freight pricing: do not quote a freight-rates USD fare as today’s price based on this congestion signal.
- Assuming locode is always present: locode may be null; do not rely on it as a primary key.
End-to-end example flow
Here is a minimal outline you can adapt for production:
- Nightly job (UTC midnight): call the endpoint with X-API-Key and port=Shekou.
- Validate success and presence of data.results[0].
- Extract congestion, ratio_vs_baseline, as_of; store to your metrics store keyed by date.
- Expose a lightweight internal API returning the latest observation for your dashboard.
- Render a badge with the congestion label and a sparkline of ratio_vs_baseline for the last 30 observation dates.
Testing strategy
Implement contract tests that assert the presence of keys: success, data, data.results[0].congestion, data.results[0].metrics.ratio_vs_baseline, and data.results[0].as_of. Your tests should tolerate extra fields and nulls where optional.
Mock failures for HTTP 429/5xx and verify exponential backoff and cache fallback. Dry-run your alerts to ensure no paging on a lagged metric; prefer low-priority notifications.
Developer FAQ
Q: How often should I poll Shekou congestion?
A: Once per day is appropriate. The signal is lagged by ~6–7 days and updates daily; more frequent polling does not improve freshness.
Q: Which fields are safe to display in a transportation dashboard?
A: congestion, metrics.ratio_vs_baseline, and as_of. These convey a clear qualitative and quantitative view with the observation date.
Q: Is this live AIS wait time?
A: No. It is a 7-day average of port calls vs a 90-day baseline from IMF PortWatch. It does not measure anchorage or berth-wait durations.
Q: Do I need a key?
A: You can call as a guest (100 requests/day per IP). For production or multi-port polling, use X-API-Key to avoid shared-IP limits.
Q: What timezone is as_of?
A: Treat as_of as a UTC date in YYYY-MM-DD format; it represents the date for the aggregated observation window.
Ready to integrate Shekou congestion into your transportation workflow? Create your account and get an API key here: Register. For field-by-field reference, parameters, and additional details, see the Documentation.