Home → Blog

You need to programmatically detect weather-driven flood disruptions that may impact shipments moving through a specific port, and you want a copy-pasteable implementation you can ship today. By the end of this guide, you’ll be able to query FreightPulse for flood-related disruptions at a port (e.g., USLAX), handle authentication with X-API-Key, validate the standard response envelope, and integrate it into a PHP workflow with production-minded error handling, plus a lightweight JavaScript example.

What you’ll query: Flood disruptions (Weather-only)

This guide focuses strictly on weather-related disruption signals—specifically floods—so you can alert, pause bookings, or reroute before impacts cascade. The lookup you’ll implement is Flood Disruptions, which surfaces natural-hazard events. Natural hazards are sourced from GDACS/USGS/NOAA only. This post does not cover strikes, labor actions, canal closures, or any non-weather category.

Illustration: How to Get Flood Disruptions

Do not quote a spot freight rate or a USD fare as today’s price in any downstream UI you build. Also, FreightPulse port congestion metrics (when you use them) are IMF PortWatch-derived, lagged approximately 6–7 days, presented as a 7-day average vs a 90-day baseline, and are not live AIS wait times.

Auth, quotas, and the response envelope

Authentication is via a header:

Every response is wrapped in a consistent envelope:

You should always check success before reading fields in data. When writing parsers, code defensively to handle nulls or unexpected shapes, and keep a copy of meta.request_id in your logs for troubleshooting with support.

Quick start: cURL for Flood Disruptions

Use this exact request to retrieve flood-related disruptions for the Los Angeles (USLAX) port. Replace the API key value with your own when you have one; for guest usage, omit the header and stay within the guest quota.

curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/disruptions?port=USLAX&type=flood"

Notes:

For more details, see the Documentation.

PHP implementation: request, validation, and safe parsing

The following PHP snippet uses cURL to call the Flood Disruptions lookup, validates the standard response envelope, and returns the decoded data for your application. It avoids hard assumptions about inner fields, since disruption payloads can evolve. Extend the data handling only after inspecting the actual fields you receive in your environment.

PHP: Minimal client with timeouts and basic error handling

<?php
function fetchFloodDisruptions(string $port, ?string $apiKey = null): array {
$url = "https://freightpulsehq.com/api/v1/disruptions?port=" . urlencode($port) . "&type=flood";

$ch = curl_init($url);
$headers = [];
if ($apiKey !== null && $apiKey !== "") {
$headers[] = "X-API-Key: " . $apiKey;
}

curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => 5, // seconds
CURLOPT_TIMEOUT => 15, // total timeout
CURLOPT_HTTPHEADER => $headers,
]);

$raw = curl_exec($ch);
$curlErr = curl_error($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($raw === false) {
throw new RuntimeException("HTTP request failed: " . $curlErr);
}
if ($status < 200 || $status >= 300) {
throw new RuntimeException("Unexpected HTTP status: $status; body: $raw");
}

$json = json_decode($raw, true);
if (!is_array($json)) {
throw new RuntimeException("Response was not valid JSON");
}

// Validate standard envelope
if (!array_key_exists('success', $json) || $json['success'] !== true) {
// Optionally, log meta.request_id if provided
$reqId = $json['meta']['request_id'] ?? 'unknown';
throw new RuntimeException("API indicated failure (request_id=$reqId)");
}
if (!array_key_exists('data', $json)) {
throw new RuntimeException("Missing data field in response");
}

// Return the data payload as-is; your app can then inspect the fields it needs.
return $json['data'];
}

try {
// Provide YOUR_API_KEY if you have one; otherwise call with null for guest mode.
$data = fetchFloodDisruptions('USLAX', 'YOUR_API_KEY');

// Example: log top-level keys and keep a copy for audit
error_log('Received disruption keys: ' . implode(',', array_keys($data)));

// TODO: Map $data to your alerting or routing logic once you review live fields.
print_r($data);
} catch (Throwable $e) {
// Surface errors to your logging/observability
error_log('Disruption fetch failed: ' . $e->getMessage());
http_response_code(502);
echo json_encode(['ok' => false, 'error' => 'Upstream fetch failed']);
}

Implementation tips:

PHP: Retrying transient failures

If you run this in a background job, consider exponential backoff for 429 or 5xx statuses. Keep total retry time bounded to protect SLAs.

<?php
function httpGetWithBackoff(string $url, array $headers = [], int $maxAttempts = 4): array {
$delayMs = 200; // initial backoff
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => $headers,
]);
$raw = curl_exec($ch);
$err = curl_error($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($raw === false) {
if ($attempt === $maxAttempts) {
throw new RuntimeException("HTTP error: " . $err);
}
} elseif ($status >= 200 && $status < 300) {
$json = json_decode($raw, true);
if (is_array($json)) return $json;
if ($attempt === $maxAttempts) {
throw new RuntimeException("Invalid JSON on final attempt");
}
} elseif (in_array($status, [429, 500, 502, 503, 504], true)) {
// retryable
} else {
throw new RuntimeException("Non-retryable status $status; body: $raw");
}

usleep($delayMs * 1000);
$delayMs = min(4000, (int)($delayMs * 2.0));
}
throw new RuntimeException("Exhausted retries");
}

function fetchFloodWithRetry(string $port, ?string $apiKey = null): array {
$url = "https://freightpulsehq.com/api/v1/disruptions?port=" . urlencode($port) . "&type=flood";
$headers = [];
if ($apiKey) $headers[] = "X-API-Key: " . $apiKey;
$json = httpGetWithBackoff($url, $headers);
if (($json['success'] ?? null) !== true) {
$reqId = $json['meta']['request_id'] ?? 'unknown';
throw new RuntimeException("API indicated failure (request_id=$reqId)");
}
if (!array_key_exists('data', $json)) {
throw new RuntimeException("Missing data in envelope");
}
return $json['data'];
}

JavaScript example: fetch flood disruptions in Node

This example fetches disruptions for USLAX and performs the same envelope checks. It prints the top-level keys of data so you can quickly see what’s available in your environment.

import fetch from 'node-fetch';

async function getFloodDisruptions(port, apiKey) {
const url = `https://freightpulsehq.com/api/v1/disruptions?port=${encodeURIComponent(port)}&type=flood`;
const headers = {};
if (apiKey) headers['X-API-Key'] = apiKey;

const res = await fetch(url, { headers, redirect: 'follow' });
if (!res.ok) {
const body = await res.text();
throw new Error(`HTTP ${res.status}: ${body}`);
}

const json = await res.json();
if (json.success !== true) {
const reqId = json.meta?.request_id ?? 'unknown';
throw new Error(`API indicated failure (request_id=${reqId})`);
}
if (!Object.prototype.hasOwnProperty.call(json, 'data')) {
throw new Error('Missing data in response');
}
return json.data;
}

(async () => {
try {
const data = await getFloodDisruptions('USLAX', 'YOUR_API_KEY');
console.log('data keys:', Object.keys(data));
} catch (err) {
console.error('Fetch failed:', err.message);
process.exitCode = 1;
}
})();

Official JSON sample: envelope and field handling

The following official sample shows the standard envelope returned by FreightPulse. Copy it as-is if you need a mocked fixture while wiring up your parser. Do not substitute your own fields in tests until your integration is complete.

{
"success": true,
"data": {
"timestamp": "2026-10-10T00:00:20+00:00",
"source": "EIA (U.S. Energy Information Administration)",
"currency": "USD",
"unit": "gallon",
"data": {
"diesel": {
"national_average": 6.199,
"change_week": -0.183,
"change_percent": -2.87,
"updated_at": "2026-10-05",
"regions": {
"east_coast": 5.951,
"midwest": 6.286,
"gulf_coast": 5.819,
"rocky_mountain": 6.267,
"west_coast": 7.229,
"california": 8.082
}
},
"gasoline": {
"national_average": 4.354,
"change_week": -0.111,
"change_percent": -2.49,
"updated_at": "2026-10-05",
"grades": {
"regular": 4.354,
"midgrade": 4.99,
"premium": 5.4
}
},
"bunker_fuel": {
"available": false,
"note": "No known free source (Rotterdam/Singapore/Houston) — requires a paid provider (e.g. Ship & Bunker, Argus)."
}
},
"historical": {
"diesel_30d_avg": 6.349,
"diesel_90d_avg": 5.686,
"diesel_yoy_change": 67,
"gasoline_30d_avg": 4.404,
"gasoline_90d_avg": 4.155,
"gasoline_yoy_change": 39.4
}
},
"meta": {
"request_id": "b089ad89-1827-4363-990a-b66fc2a31258"
}
}

Field notes you will actually use during integration:

While the inner fields above illustrate units, time, and structure, you should still code to the envelope so your client remains robust for flood disruptions.

Operational details that will save you time

Testing locally and promoting to production

For local development, start with the official cURL and confirm you receive the standard envelope. Next, run the PHP client and log the keys present under data for your target port. Avoid schema-guessing—introspect the payload you receive and then explicitly map the fields you want to alert on.

In production:

Common pitfalls and how to avoid them

FAQ

Q: Do I need an API key?
A: You can call the endpoint without a key, but you’re limited to 100 requests/day per IP. Add X-API-Key: YOUR_API_KEY to raise limits.

Q: What parameters are supported for flood lookups?
A: Use port (e.g., USLAX) and type=flood as shown in the quick-start cURL. See the Documentation for any additional options.

Q: How should I handle the response schema?
A: First validate the envelope (success and data). Then introspect data in your environment and map only the fields you need. Keep meta.request_id for logs.

Q: Are the signals real-time?
A: Natural hazard feeds can be near-real-time depending on the source, but port congestion context is IMF PortWatch, lagged roughly 6–7 days and not live AIS wait times.

Q: Can I display freight rates alongside disruptions?
A: Do not quote a freight-rates USD fare as today’s price in conjunction with this data.

Ready to put flood disruption detection into production? Create your account and get an API key now: Register. For endpoint details and integration patterns, keep the docs open: Documentation.