Home → Blog

You need to programmatically detect wildfire-related weather disruptions that could affect a specific port’s operations and routing. By the end of this guide, you’ll be able to query FreightPulse for “Wildfire Disruptions” at a given port, authenticate with X-API-Key, parse the response envelope, and ship a production-safe PHP integration with sensible caching and error handling.

What this integration covers (and what it doesn’t)

This article focuses on Weather disruptions specifically tied to natural hazards—wildfires—sourced from GDACS/USGS/NOAA. It does not cover labor strikes, canal closures, or unrelated operational issues. It also does not surface or quote freight-rate fares as today’s price. If you need broader coverage, consult the FreightPulse docs and consider parallel endpoints in your own application layer, but keep the wildfire lookup isolated per this guide.

Illustration: How to Get Wildfire Disruptions

Facts you should copy into your implementation

Endpoint you will call for Weather: Wildfire Disruptions

Use the disruptions endpoint with type=wildfire and a specific port code. The example below queries Los Angeles (USLAX):

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

Keep the Authorization header exactly as shown (X-API-Key) and substitute only the port code or query parameters explicitly documented. Do not add undocumented parameters.

Official sample response envelope and how to interpret it

The official sample below shows the response envelope and meta shape you should expect to parse in your client. Copy it exactly for tests that validate envelope, types, and parsing flow.

{
"success": true,
"data": {
"timestamp": "2026-10-11T00:00:19+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": "82f8dc19-b0a6-4249-aea0-584078406a33"
}
}

What you need to parse consistently across responses:

Field names beyond the envelope may vary by resource. Always gate your application logic on the envelope fields first (success, data, meta) and then read the resource-specific structures present for wildfire disruptions in your live calls.

PHP: Build the Wildfire Disruptions lookup

The snippet below shows a production-ready PHP approach using cURL. It sends the X-API-Key header, validates the success flag, and guards against malformed JSON. You can adapt the decoding section to your storage schema or alerting system.

PHP steps

  1. Set the endpoint to /api/v1/disruptions with type=wildfire and your target port (e.g., USLAX).
  2. Add the X-API-Key header with YOUR_API_KEY. If you do not have a key, the guest limit applies (100 requests/day per IP).
  3. Parse the JSON and first check success. If false (or missing), log meta.request_id and halt.
  4. Use data.timestamp to align caching and freshness. It’s ISO-8601 with timezone info.
  5. Only use fields present in the live response; do not assume undocumented keys.
<?php
$endpoint = 'https://freightpulsehq.com/api/v1/disruptions?port=USLAX&type=wildfire';
$ch = curl_init($endpoint);

$headers = [
'X-API-Key: YOUR_API_KEY',
'Accept: application/json'
];

curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 20
]);

$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($errno !== 0) {
error_log('FreightPulse request error: ' . $error);
http_response_code(502);
exit('Upstream request failed');
}

if ($httpCode < 200 || $httpCode >= 300) {
error_log('FreightPulse non-2xx: HTTP ' . $httpCode . ' body=' . substr($response, 0, 2000));
http_response_code(502);
exit('Unexpected status from upstream');
}

$decoded = json_decode($response, true);
if (!is_array($decoded)) {
error_log('Invalid JSON from FreightPulse: ' . substr($response, 0, 1000));
http_response_code(502);
exit('Invalid upstream JSON');
}

if (!isset($decoded['success']) || $decoded['success'] !== true) {
$reqId = isset($decoded['meta']['request_id']) ? $decoded['meta']['request_id'] : 'unknown';
error_log('FreightPulse reported unsuccessful response. request_id=' . $reqId);
http_response_code(502);
exit('Upstream returned unsuccessful response');
}

// The envelope is consistent: success, data, meta
$data = isset($decoded['data']) ? $decoded['data'] : [];
$meta = isset($decoded['meta']) ? $decoded['meta'] : [];
$timestamp = isset($data['timestamp']) ? $data['timestamp'] : null;

// Example: route to your wildfire disruption handler
// DO NOT invent events; consume what the API actually returns for this lookup.
$disruptionsPayload = $data;

// Cache decision: prefer server-provided timestamp if present
$ttlSeconds = 300; // adjust per your tolerance and update frequency
if ($timestamp !== null) {
// If you have a cache layer, you can use this timestamp for staleness checks.
}

// Persist, alert, or render the disruptions payload as needed.
header('Content-Type: application/json');
echo json_encode([
'ok' => true,
'fetched_at' => gmdate('c'),
'request_id' => isset($meta['request_id']) ? $meta['request_id'] : null,
'timestamp' => $timestamp,
'payload' => $disruptionsPayload
]);

JavaScript example: fetch and read the envelope

This Node.js/JavaScript snippet calls the same endpoint and extracts envelope fields. Adapt the inner payload mapping only to keys you actually see at runtime.

import fetch from 'node-fetch';

async function getWildfireDisruptions(portCode = 'USLAX') {
const url = `https://freightpulsehq.com/api/v1/disruptions?port=${encodeURIComponent(portCode)}&type=wildfire`;
const res = await fetch(url, {
headers: {
'X-API-Key': 'YOUR_API_KEY',
'Accept': 'application/json'
},
timeout: 20000
});

if (!res.ok) {
const text = await res.text();
throw new Error(`Non-2xx from FreightPulse: HTTP ${res.status} body=${text.slice(0, 500)}`);
}

const body = await res.json();
if (!body || body.success !== true) {
const reqId = body && body.meta ? body.meta.request_id : 'unknown';
throw new Error(`Unsuccessful response (request_id=${reqId})`);
}

const data = body.data || {};
const meta = body.meta || {};
const timestamp = data.timestamp || null;

// Only use fields present; do not assume undocumented structures.
return {
timestamp,
payload: data,
requestId: meta.request_id || null
};
}

getWildfireDisruptions('USLAX')
.then(result => {
console.log('Disruptions fetched at', new Date().toISOString());
console.log('API timestamp:', result.timestamp);
console.log('Request ID:', result.requestId);
console.log('Payload keys:', Object.keys(result.payload));
})
.catch(err => {
console.error('Error fetching disruptions:', err.message);
});

Operational notes that will save you time

Testing your integration with USLAX

Start with a fixed port code (USLAX) to simplify logging and comparisons across environments. Keep a trace of:

Once stable, parameterize the port code via config or a safe allowlist. Avoid user-supplied free text mapped directly into the URL; validate input against a known port code directory maintained in your codebase or database.

Data handling patterns for production

Security and key management

Development and documentation links

For parameter coverage, envelope clarifications, and endpoint-specific notes, see the official docs. When you are ready to move beyond the guest cap, register for an API key.

FAQ

Do I need an API key to get started?
You can start without a key under the guest limit of 100 requests/day per IP. For sustained use or higher volume, add the X-API-Key header with YOUR_API_KEY.

Is port congestion in this Weather workflow live?
No. Port congestion is IMF PortWatch with a ~6–7 day lag (7-day average vs 90-day baseline). Do not present it as live AIS wait times.

What timestamps should I rely on for freshness?
Use data.timestamp from the response. It is an ISO-8601 value with timezone. Prefer it over local receipt time for cache control and audits.

Can I include strike or canal closure data here?
No. This guide is limited to natural-hazard Weather data for wildfires. Do not mix in strikes or canals for this lookup.

Can I display a freight-rate USD fare with these disruptions?
Do not quote a freight-rates USD fare as today’s price in this workflow. Keep fare quotes out of the wildfire disruptions surface.

Next steps

Stand up the PHP endpoint with the disruptions request, verify the envelope with the official sample, and add robust logging around success, data.timestamp, and meta.request_id. When ready to exceed guest limits and automate across ports, create your API key via Register.