You need a reliable way to programmatically check current congestion levels at the Port of New York–New Jersey so operations teams can adjust sailings, drayage, or yard plans. By the end of this guide, you’ll be able to call a production API in Python and curl to fetch congestion for New York–New Jersey, interpret the returned fields, and integrate the data safely with caching and monitoring.
What this API returns and what it does not
The congestion endpoint returns a standardized envelope with a success flag and a data object. Within that, you get a results array for the specified port, a global summary, and metadata about the source and methodology. Congestion here is computed from IMF PortWatch (UN Global Platform AIS data) and reflects a 7-day rolling average versus a 90-day baseline. It is updated daily but is lagged by about 6–7 days and does not measure real-time vessel wait or anchorage times.
Key takeaways for developers integrating transportation operations:
- Data source: IMF PortWatch, lagged ~6–7 days, updated daily (not live AIS wait-time tracking).
- Core fields: congestion (categorical), metrics.ratio_vs_baseline (float), and as_of (YYYY-MM-DD date of the series).
- Do not treat this as a minute-by-minute operational feed; treat it as a near-real-time planning indicator.
Endpoint and authentication
Use HTTP GET to query the congestion endpoint for New York–New Jersey (pass “New York” as the port parameter):
- Method: GET
- URL: https://freightpulsehq.com/api/v1/port-congestion?port=New%20York
- Auth: Header X-API-Key: YOUR_API_KEY
- Rate limits: Guests without a key are limited to 100 requests per day per IP.
- Response envelope: {"success": true, "data": {...}}
The API returns JSON with a single “results” entry for the requested port. The congestion level is derived from a 7-day average of port calls compared with a 90-day baseline for the same port.
Reference the official docs here: Documentation.
Copy-pasteable curl example
Call the endpoint for New York–New Jersey by specifying port=New%20York in the query string and sending your API key in the X-API-Key header.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=New%20York"
Official JSON response and fields you will use
The response format below is the official sample for New York–New Jersey. Integrations should not assume additional fields beyond those shown. Read congestion, metrics.ratio_vs_baseline, and as_of for most routing and planning logic.
{
"success": true,
"data": {
"results": [
{
"port": "New York-New Jersey",
"locode": null,
"country": "United States",
"congestion": "moderate",
"as_of": "2026-10-16",
"metrics": {
"recent_avg_portcalls_per_day": 11.1,
"baseline_avg_portcalls_per_day": 9.9,
"ratio_vs_baseline": 1.13
}
}
],
"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": "942b5d69-b69a-4689-8582-0d6df4d9f10c"
}
}
What to read from the payload:
- data.results[0].congestion: a categorical level such as “low”, “moderate”, or “high”.
- data.results[0].as_of: ISO date (YYYY-MM-DD). Treat as the effective date of the aggregated 7-day series. Timezone: date-level (no time-of-day provided).
- data.results[0].metrics.ratio_vs_baseline: float; 1.0 equals baseline congestion; values above 1.0 indicate more port calls than the 90-day baseline.
- data.meta.data_lag_days: string explaining the ~6–7 day lag due to source methodology.
Python integration: request, parse, and guardrails
The snippet below fetches the New York–New Jersey congestion reading, extracts the key fields used by operations planners, and shows minimal guardrails around missing keys and request failures. It preserves the response envelope shape described above.
import os
import sys
import json
import time
from datetime import datetime, timezone
import requests
API_URL = "https://freightpulsehq.com/api/v1/port-congestion"
PORT_PARAM = "New York" # New York-New Jersey
API_KEY = os.environ.get("FREIGHTPULSE_API_KEY", "YOUR_API_KEY")
def fetch_congestion(session: requests.Session) -> dict:
headers = {
"X-API-Key": API_KEY
}
params = {
"port": PORT_PARAM
}
resp = session.get(API_URL, headers=headers, params=params, timeout=20)
resp.raise_for_status()
return resp.json()
def parse_congestion(payload: dict) -> dict:
# Expected envelope: { "success": true, "data": { "results": [ ... ] } }
if not isinstance(payload, dict) or not payload.get("success", False):
raise ValueError("API reported unsuccessful response")
data = payload.get("data", {})
results = data.get("results", [])
if not results:
raise ValueError("No results for requested port")
first = results[0]
congestion = first.get("congestion")
as_of = first.get("as_of")
metrics = first.get("metrics", {})
ratio = metrics.get("ratio_vs_baseline")
# Return only the essentials needed by downstream systems
return {
"port": first.get("port"),
"congestion": congestion,
"ratio_vs_baseline": ratio,
"as_of": as_of
}
def main():
with requests.Session() as session:
try:
payload = fetch_congestion(session)
core = parse_congestion(payload)
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(1)
# Print a compact summary for logs/alerts
print(json.dumps(core, separators=(",", ":"), ensure_ascii=False))
# Optional: basic decision rule for planning systems
level = (core.get("congestion") or "").lower()
ratio = core.get("ratio_vs_baseline")
if level == "high" or (isinstance(ratio, (int, float)) and ratio >= 1.2):
# Example action: bump safety lead times, notify ops
print("Advisory: Elevated congestion at New York–New Jersey.", file=sys.stderr)
if __name__ == "__main__":
main()
Interpreting congestion for transportation decisions
Operations teams typically consume three fields for routing and scheduling logic:
- congestion: convert “low”, “moderate”, “high” to operational states. For example, adjust buffer times in berth windows or schedule drayage shifts differently.
- ratio_vs_baseline: use thresholding (e.g., 1.1, 1.2) for quantitative gating, such as toggling extra yard capacity or pulling forward pickups.
- as_of: ensure your planning date bands align; do not treat readings newer than the lag horizon as live status.
Because measurements are based on port calls, they approximate relative throughput, not queueing time. For dynamic wait-time predictions, pair this series with your internal dwell telemetry or carrier advisories.
Reliability notes: lag, caching, and retries
Lag and cadence: the data is derived from IMF PortWatch and is typically ~6–7 days behind the current calendar date, updated daily. Treat it as a near-real-time indicator suitable for planning horizons of days, not hours.
Caching: since values update daily and are date-stamped, caching per-port for 24 hours is reasonable. At minimum, cache until the as_of date changes on subsequent calls.
Retries and backoff: implement exponential backoff on non-2xx responses and connection errors. Honor the guest limit of 100 requests/day per IP if you do not send an API key.
Envelope stability: check the top-level success flag before reading data.results. If results is empty, treat it as no available reading for the requested port.
Minimal integration checklist for New York–New Jersey
- Send X-API-Key: YOUR_API_KEY in the request header.
- Query GET /api/v1/port-congestion?port=New%20York.
- Parse success, then data.results[0] for congestion, metrics.ratio_vs_baseline, and as_of.
- Log data.meta.source and data.meta.data_lag_days for observability.
- Cache by as_of to avoid redundant processing on the same daily snapshot.
- Do not substitute this for live AIS wait times; this is a 7-day average vs a 90-day baseline.
Common pitfalls and how to avoid them
- Treating the series as real-time: pin any operational decisions to the as_of date and the stated lag.
- Overfitting thresholds: start with coarse bands around ratio_vs_baseline (for example, <= 1.0 low, 1.0–1.2 moderate, > 1.2 high) and refine with your historical SLA outcomes.
- Ignoring missing fields: defensive parsing prevents outages if the metrics object is unavailable for a given date.
- Skipping the envelope: always check success, then dig into data.results.
FAQ
Is this live AIS wait-time data?
No. The congestion series uses IMF PortWatch with a ~6–7 day lag and a 7-day rolling average versus a 90-day baseline. It does not measure vessel wait or anchorage time in real time.
What authentication is required?
Send your key in the X-API-Key header. Guests without a key are limited to 100 requests per day per IP. For production use, register for an API key.
What timezone are timestamps in?
The as_of field is a date in YYYY-MM-DD format for the aggregated time window. No time-of-day is returned; treat it as a date-level UTC value for caching and reporting.
Is there pagination?
For a single-port query, the response provides one entry in data.results. Pagination is not applicable for this use case.
Can I use this to quote freight rates?
No. This endpoint measures congestion derived from port calls. It should not be used to quote freight rates or today’s transport pricing.
Next step
Get an API key and wire the endpoint into your transportation planning workflow. Start here: Register. For implementation details, field definitions, and envelope structure, see the Documentation.