Teams moving containers through the Port of Hamburg (DEHAM) need a fast way to programmatically check congestion conditions and pair that insight with current fuel cost signals for voyage planning. By the end of this guide, you will call the Hamburg congestion endpoint with a real curl command, parse the response in JavaScript, and add a PHP snippet that fetches FreightPulse’s EIA-based fuel price metric for Transportation operations.
What the Hamburg congestion series represents
FreightPulse’s port congestion data for Hamburg is sourced from IMF PortWatch and is intentionally lagged by roughly 6–7 days. The signal is a 7‑day average compared against a 90‑day baseline, and it is not a live AIS vessel wait-time feed. This design makes it stable for operational dashboards where day-to-day noise hurts decision quality.
Important implementation notes you should copy exactly:
- Auth: header X-API-Key: YOUR_API_KEY. Guest without key: 100 requests/day per IP.
- Envelope: {"success":true,"data":{...}}
- Port congestion is IMF PortWatch, lagged ~6-7 days, 7-day avg vs 90-day baseline — not live AIS.
- Do not quote a freight-rates USD fare as today’s price.
- Port: Hamburg (DEHAM)
No official congestion JSON is published for DEHAM in the docs. You will see the curl request and the expected field names so you can integrate cleanly once your key is provisioned.
Authentication, headers, and request volume
Every authenticated request uses the header X-API-Key with your issued key. If you do not include a key, you are treated as a guest. Guests are limited to 100 requests per day per IP, which is enough for local prototyping but typically not for production. Use your own key to avoid throttling during deployments and CI runs.
All JSON responses are wrapped in a standard envelope of the form {"success":true,"data":{...}}. Your integration should check success first, then read data. Treat any HTTP 4xx/5xx as non-retryable unless your job runner has explicit backoff logic.
Hamburg congestion: curl you can paste
Use this request to fetch the DEHAM congestion snapshot. Keep the exact header and query parameter casing.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/port-congestion?port=DEHAM"
Note the port query parameter is the UN/LOCODE “DEHAM”. The endpoint returns a time-stamped congestion reading built as a 7-day average versus a 90-day baseline. Because the series is lagged ~6–7 days, do not display it as an estimate of today’s queue or wait time.
Minimal JSON you should expect and how to read it
The official docs do not publish a concrete DEHAM JSON sample. The snippet below is illustrative and shows the documented field names only. The real values will differ.
{
"success": true,
"data": {
"port": "DEHAM",
"congestion": <number>,
"ratio_vs_baseline": <number>,
"as_of": "YYYY-MM-DD"
}
}
Field usage in your code:
- data.port: Always validate it equals DEHAM for Hamburg-specific widgets.
- data.congestion: The current 7-day congestion signal. Treat as a normalized numeric measure; do not reinterpret it as hours or days.
- data.ratio_vs_baseline: The ratio relative to the 90-day baseline. Values above 1.0 indicate above-baseline congestion; below 1.0 indicate below-baseline, without implying a wait-time translation.
- data.as_of: ISO date for the end of the 7-day window. Expect a lag of roughly one week versus the wall clock.
JavaScript example: fetch and normalize DEHAM congestion
This JavaScript example calls the same endpoint and extracts the three fields your UI or alerting job will actually use. Add simple guards so a missing field does not break your pipeline.
async function fetchHamburgCongestion() {
const url = "https://freightpulsehq.com/api/v1/port-congestion?port=DEHAM";
const res = await fetch(url, {
headers: { "X-API-Key": "YOUR_API_KEY" },
timeout: 15000
});
if (!res.ok) {
throw new Error(`HTTP ${res.status} while fetching DEHAM congestion`);
}
const body = await res.json();
if (!body || body.success !== true || !body.data) {
throw new Error("Unexpected envelope");
}
const { port, congestion, ratio_vs_baseline, as_of } = body.data;
if (port !== "DEHAM") {
throw new Error(`Mismatched port: ${port}`);
}
// Use safe parsing and defaults
const value = Number(congestion);
const ratio = Number(ratio_vs_baseline);
const date = String(as_of);
if (!Number.isFinite(value) || !Number.isFinite(ratio) || !date) {
throw new Error("Incomplete DEHAM payload");
}
return { port, value, ratio, as_of: date };
}
// Example usage:
fetchHamburgCongestion()
.then(({ port, value, ratio, as_of }) => {
console.log(`Port ${port} congestion (as_of ${as_of}): value=${value}, ratio_vs_baseline=${ratio}`);
})
.catch(err => {
console.error("DEHAM congestion error:", err);
});
PHP guide: pull the EIA-based fuel price metric
Many Transportation teams pair the Hamburg congestion read with a current fuel price signal to budget bunkering or overland trucking legs. FreightPulse exposes a fuel price endpoint derived from the EIA metric. The call uses the same X-API-Key header and returns the standard envelope. The example below demonstrates a minimal PHP client.
Do not assume a national average or invent a price. If you display a value, ensure it comes directly from the API response.
<?php
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => "https://freightpulsehq.com/api/v1/fuel-prices",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-API-Key: YOUR_API_KEY",
"Accept: application/json"
],
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 15,
]);
$response = curl_exec($ch);
if ($response === false) {
throw new RuntimeException("cURL error: " . curl_error($ch));
}
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode < 200 || $httpCode >= 300) {
throw new RuntimeException("HTTP $httpCode from fuel-prices");
}
$data = json_decode($response, true);
if (!isset($data["success"]) || $data["success"] !== true || !isset($data["data"])) {
throw new RuntimeException("Unexpected envelope from fuel-prices");
}
// Do not fabricate units or currency; read them from the payload if provided.
// Here we defensively access commonly expected fields while tolerating absence.
$fuel = $data["data"];
$price = isset($fuel["price"]) ? $fuel["price"] : null;
$unit = isset($fuel["unit"]) ? $fuel["unit"] : null;
$currency = isset($fuel["currency"]) ? $fuel["currency"] : null;
$asOf = isset($fuel["as_of"]) ? $fuel["as_of"] : null;
// Only render values that actually exist in the response.
echo "Fuel metric as_of: " . ($asOf ?? "n/a") . PHP_EOL;
if ($price !== null) {
$parts = [];
$parts[] = "price={$price}";
if ($unit !== null) $parts[] = "unit={$unit}";
if ($currency !== null) $parts[] = "currency={$currency}";
echo implode(" ", $parts) . PHP_EOL;
}
?>
If you need exact field semantics, refer to the API reference. The envelope and header conventions are the same across endpoints, so the authentication and error handling patterns above will carry over to production code.
For the latest endpoint details and field dictionaries, see the Documentation.
Caching, timestamps, units, and other practical details
Congestion lag and cadence: Hamburg’s congestion series is built as a 7-day moving average and is updated on a lag of about 6–7 days. A daily fetch is typically sufficient; more frequent polling will not return fresher values.
as_of semantics: Treat as_of as an ISO calendar date (UTC) marking the end of the averaging window. If you compute week-over-week comparisons, align by date rather than wall-clock time.
Caching: Because the series is lagged, a 24-hour cache TTL is a safe starting point for server-side caching and CDN edges. For clients with strict SLAs, fetch at a scheduled hour and invalidate downstream caches immediately after a successful pull.
Units: The congestion value is a normalized metric; do not translate it into hours, queues, or monetary costs without a documented mapping. The ratio_vs_baseline is a unitless ratio. For fuel prices, use the unit and currency as provided by the API; do not substitute a “national average” or assume a particular currency if the payload does not state it.
Pagination: The DEHAM endpoint above is shown as a snapshot read. If you need a historical range, consult the API reference for a time-series variant and apply pagination or cursor parameters as documented.
Error handling and retries: Handle HTTP 429 by backing off; guests share the 100 requests/day per IP pool. For 5xx responses, implement exponential backoff with jitter. Always validate the {"success":true,"data":{...}} envelope before dereferencing fields.
Input validation and safe rendering
Always hard-code the Hamburg code DEHAM in your requests and verify that the response data.port equals DEHAM before updating a DEHAM panel. If your UI supports multiple ports, route each response to the correct widget by port code rather than by URL path.
When logging or alerting on ratio_vs_baseline, round to a fixed number of decimals and include the as_of date, e.g., “DEHAM congestion ratio_vs_baseline=1.12 as_of 2026‑05‑03.” This prevents misinterpretation as a live queue estimate and gives operators context for the lag.
Joining congestion with fuel price logic in your pipeline
Many planning jobs compute a simple decision matrix keyed by port condition and current fuel cost signal. For example, if Hamburg is materially above baseline (ratio_vs_baseline > 1.0) in your own thresholds and fuel is steady, you might prefer routing buffers over schedule compression. Your code should keep these concerns decoupled: congestion is a port-level, lagged operational indicator; fuel is a market-level cost input.
In batch workflows, fetch congestion first, validate the lag via as_of, cache it, then fetch the fuel metric. Do not merge data across different as_of dates without labeling the join; store both timestamps explicitly in your warehouse rows to maintain provenance.
Testing, observability, and deployment notes
Use the guest quota (100 requests/day per IP) for local development and CI smoke tests that run sparingly. Provision a real X-API-Key for staging and production to avoid shared-IP throttling. In canary deployments, ship both the raw envelope and extracted fields to your logs for a week to verify stability before tightening parsers.
Add budget alerts at the job layer rather than polling faster: the DEHAM signal’s lag means re-polling will not help you catch intra-day shifts. Push updates to downstream caches after a new as_of date appears to keep dashboards consistent across services.
Troubleshooting common pitfalls
- Seeing “today” in dashboards: Label charts with as_of to avoid the impression of real-time AIS wait times. This is a 7-day average vs a 90-day baseline with a ~6–7 day lag.
- Unexpected nulls: Treat congestion and ratio fields as required; if missing, keep the last known good value and flag the record to your telemetry instead of zeroing out the gauge.
- Auth errors: Ensure the header key is exactly X-API-Key and not Authorization. Keys are case-sensitive; copy them as issued.
- Overfetching: If you poll more than daily, you may hit guest limits and still not get fresher data. Cache and align fetches to a fixed UTC time.
FAQ
Is the Hamburg congestion metric a live estimate of vessels waiting at berth?
No. It is derived from IMF PortWatch, presented as a 7-day average versus a 90-day baseline, and is typically lagged by about 6–7 days. It is not a live AIS wait-time feed.
Can I call the Hamburg endpoint without an API key?
Yes, but you are limited to 100 requests per day per IP as a guest. Use X-API-Key: YOUR_API_KEY for sustained integrations.
What fields should I parse from the congestion response?
Use data.port (validate DEHAM), data.congestion (normalized value), data.ratio_vs_baseline (unitless ratio), and data.as_of (ISO date). Always check the {"success":true,"data":{...}} envelope first.
How should I cache the Hamburg congestion series?
Because the series is lagged and updates infrequently, a 24-hour TTL is a reasonable default. Invalidate caches when a new as_of date appears.
How do I retrieve fuel pricing to pair with congestion?
Call GET /api/v1/fuel-prices with the X-API-Key header. Read values from the payload as provided; do not infer or invent a national average or currency if not present.
Next step
Set up your API access and wire these calls into your job runner so your Hamburg (DEHAM) dashboards and planning scripts are both accurate and simple to maintain. Create an account and get your key here: Register. For full endpoint details and field dictionaries, see the Documentation.