Your operations team needs a reliable way to detect volcano-related weather disruptions that could affect cargo flows at key ports. By the end of this guide, you’ll be able to query FreightPulse for “Volcano Disruptions,” integrate the response into a PHP service, and safely handle authentication, envelopes, and downstream parsing without guessing fields or quoting non-weather data as live prices.
What you can and cannot retrieve with the Volcano Disruptions lookup
The “Volcano Disruptions” lookup returns natural-hazard information only. It focuses on events sourced from GDACS, USGS, and NOAA that are relevant to port operations. Do not use it for labor actions, canal restrictions, or other non-weather categories.
- Lookup name: Volcano Disruptions
- Envelope: every response is wrapped in {"success": true, "data": {...}}
- Auth: supply your key via header X-API-Key: YOUR_API_KEY (guest access without a key is limited to 100 requests/day per IP)
- Do not quote a freight-rates USD fare as today’s price; this endpoint is about weather-related disruptions, not live rates
- Port congestion note (related FreightPulse context): congestion metrics come from IMF PortWatch and are lagged about 6–7 days (7-day average vs 90-day baseline). They are not live AIS wait times
If you need to build beyond the examples here, refer to the official Documentation.
Authentication and request envelope
FreightPulse uses a simple header for authentication. Provide your key exactly as shown below. Without a key, a guest is limited to 100 requests per day per IP. Successful requests return an envelope with top-level "success" and a "data" object you will parse.
- Header: X-API-Key: YOUR_API_KEY
- Envelope shape: {"success": true, "data": {...}}
- On errors, check HTTP status and parse the JSON safely before accessing nested fields
Quick test with curl (Volcano Disruptions for USLAX)
Run this from a shell to validate your connectivity and authentication. Replace YOUR_API_KEY with your actual key.
curl -H "X-API-Key: YOUR_API_KEY" "https://freightpulsehq.com/api/v1/disruptions?port=USLAX&type=volcano"
Notes:
- port=USLAX filters disruptions affecting the Port of Los Angeles
- type=volcano restricts the query to volcano-related weather hazards
- The response will be JSON. Always check "success" before reading the "data" payload
PHP integration guide for the FreightPulse Volcano Disruptions lookup
This section shows a production-ready PHP pattern that calls the endpoint, validates the response envelope, and makes no assumptions about optional fields that are not documented here.
1) Build a minimal HTTP client with timeouts and headers
Use PHP cURL with explicit timeouts and the X-API-Key header. Keep retries modest and exponential if you add them in your environment.
<?php
declare(strict_types=1);
function fetchVolcanoDisruptions(string $portCode, string $apiKey): array {
$url = 'https://freightpulsehq.com/api/v1/disruptions?port=' . rawurlencode($portCode) . '&type=volcano';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => 5, // seconds
CURLOPT_TIMEOUT => 15, // total seconds
CURLOPT_HTTPHEADER => [
'Accept: application/json',
'X-API-Key: ' . $apiKey,
],
]);
$body = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($errno !== 0) {
throw new RuntimeException('Network error calling FreightPulse: ' . $error, $errno);
}
if ($status < 200 || $status >= 300) {
throw new RuntimeException('Unexpected HTTP status from FreightPulse: ' . $status);
}
if ($body === false || $body === '') {
throw new RuntimeException('Empty response from FreightPulse');
}
$json = json_decode($body, true);
if (!is_array($json)) {
throw new RuntimeException('Invalid JSON returned by FreightPulse');
}
// Enforce the documented envelope
if (!array_key_exists('success', $json) || $json['success'] !== true) {
// If success is false or missing, surface a generic error; optionally log the full body
throw new RuntimeException('FreightPulse indicates an unsuccessful request');
}
if (!array_key_exists('data', $json) || !is_array($json['data'])) {
throw new RuntimeException('FreightPulse payload missing data object');
}
return $json['data'];
}
// Example usage:
try {
$data = fetchVolcanoDisruptions('USLAX', 'YOUR_API_KEY');
// At this point, $data contains the disruptions payload.
// Do not assume specific fields unless you have them from the docs.
// Safely probe for keys before accessing them.
if (isset($data['events']) && is_array($data['events'])) {
foreach ($data['events'] as $event) {
// Only read keys if they exist; avoid assuming field names
$id = $event['id'] ?? '(no-id)';
$severity = $event['severity'] ?? '(n/a)';
$reportedAt = $event['reported_at'] ?? '(n/a)';
echo "Event {$id} | Severity: {$severity} | Reported: {$reportedAt}\n";
}
} else {
echo "No events array present; nothing to display.\n";
}
} catch (Throwable $e) {
// Production systems should log details and surface a user-friendly message
error_log($e->getMessage());
echo "Failed to load volcano disruptions.";
}
Recommendations:
- Set both connect and total timeouts to avoid hung sockets
- Check the "success" flag before reading "data"
- Probe for fields defensively because this guide does not invent or fix a schema
- Cache recent responses server-side to stay well within rate limits; a short TTL (e.g., a few minutes) is typical for hazard lookups
JavaScript example: fetch volcano disruptions for USLAX
This snippet uses the same endpoint. It demonstrates basic error handling and reading the envelope without assuming optional fields beyond the documented success/data structure.
async function getVolcanoDisruptions(port, apiKey) {
const url = `https://freightpulsehq.com/api/v1/disruptions?port=${encodeURIComponent(port)}&type=volcano`;
const res = await fetch(url, {
headers: {
'Accept': 'application/json',
'X-API-Key': apiKey
}
});
if (!res.ok) {
throw new Error(`HTTP ${res.status} from FreightPulse`);
}
const payload = await res.json();
if (!payload || payload.success !== true || typeof payload.data !== 'object') {
throw new Error('Invalid FreightPulse envelope');
}
// Handle the data object carefully; do not assume undocumented fields
const data = payload.data;
// If an events array exists, iterate safely
if (Array.isArray(data.events)) {
return data.events.map(evt => ({
id: evt.id ?? null,
severity: evt.severity ?? null,
reported_at: evt.reported_at ?? null
}));
}
// If no events array, return the entire data object for caller-side handling
return data;
}
// Example usage:
getVolcanoDisruptions('USLAX', 'YOUR_API_KEY')
.then(eventsOrData => {
console.log('Volcano disruptions:', eventsOrData);
})
.catch(err => {
console.error('Failed to load volcano disruptions:', err);
});
Official sample response and what to use from it
FreightPulse samples share a consistent success/data envelope. The official blocks below must be copied exactly as-is. While this sample’s inner fields are about fuel prices, you’ll use it to pattern-match the top-level structure and safe parsing for all weather lookups (including volcano disruptions).
{
"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"
}
}
How to apply this to volcano disruptions parsing:
- Check success (boolean) before using any content
- Expect a data object; do not assume subkeys unless you have them from the docs
- Meta.request_id is useful for logging and tracing
- Timestamps are ISO 8601 with timezone offsets; store and compare in UTC to avoid drift
Practical implementation details that save time
- Authentication: always send X-API-Key: YOUR_API_KEY. For guest testing without a key, the limit is 100 requests/day per IP; implement client-side caching during development to avoid rate surprises
- Envelope: production code should fail fast if "success" is not true or if "data" is missing
- Timestamps and timezone: treat all timestamps as ISO 8601; normalize to UTC in your database and UI
- Caching: hazards don’t change every second; a small TTL (e.g., 1–5 minutes) reduces cost and latency while staying fresh
- Pagination: if the API returns many events, handle pagination per the docs; do not assume unbounded arrays
- Idempotency: read operations don’t mutate state; you can safely retry GETs on transient errors with backoff
- Port congestion context: remember that FreightPulse’s congestion data (IMF PortWatch) is lagged 6–7 days; do not treat it as live AIS wait times
- Currency and fares: the disruptions lookup is weather-only; do not quote a freight-rates USD fare as “today’s price” from this endpoint
End-to-end flow: from request to dashboard
Here is a robust flow that aligns with the envelope and hazard scope:
- Build the URL with your target port (e.g., USLAX) and type=volcano
- Send the request with X-API-Key and a 10–15 second total timeout
- On 2xx, parse JSON; verify success === true and that data is an object
- Extract only documented or present fields. If events is provided, loop defensively, checking keys before use
- Cache the sanitized result for a short TTL; display UTC timestamps in your UI; include request_id in your logs
- On errors or empty results, show a clear “No volcano disruptions detected” message without guessing causes
Testing strategies and edge cases
- No-current-events day: the endpoint may return an empty set for a port; this is not an error
- Backfill runs: if your jobs execute after local midnight UTC, ensure you handle late-arriving updates by comparing ISO timestamps, not local dates
- Intermittent network failures: implement one or two retries with exponential backoff; do not retry indefinitely
- Schema drift: since this guide does not define the full disruptions schema, guard every optional field access with isset checks
Security and operational hygiene
- Never embed your API key in client-side code; keep it server-side
- Rotate keys periodically; log meta.request_id and HTTP status for diagnostics
- Validate JSON sizes and implement per-request timeouts to avoid resource exhaustion
FAQ
Q: Can I call the disruptions endpoint without a key?
A: Yes, as a guest you get 100 requests per day per IP. For production, use X-API-Key: YOUR_API_KEY to avoid rate limits and improve reliability.
Q: Are volcano disruptions based on live AIS wait times?
A: No. FreightPulse’s related congestion context is based on IMF PortWatch and is lagged about 6–7 days (7-day average vs 90-day baseline). The volcano disruptions lookup is focused on natural hazards (GDACS/USGS/NOAA), not live AIS.
Q: Can I rely on a fixed field list inside data?
A: Do not assume undocumented fields. Always validate that fields exist before reading them. The only guaranteed structure here is the top-level envelope.
Q: Can I quote a USD freight rate from this API as a current price?
A: No. Do not quote a freight-rates USD fare as today’s price from this weather disruptions endpoint.
Q: What’s the best way to cache results?
A: Use a short TTL (e.g., 1–5 minutes) and key by the exact query (port+type). Normalize timestamps to UTC for consistent cache invalidation.
Ready to integrate the Volcano Disruptions lookup for your ports? Create an account and get your API key here: Register. For endpoint and field references, see the Documentation.