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.
Facts you should copy into your implementation
- 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.
- Lookup: Wildfire Disruptions
- Natural hazards only (GDACS/USGS/NOAA). Do not invent an event or cover strikes/canals.
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:
- success: Boolean. Always check this before reading payload fields.
- data: Object. The top-level container for the resource’s payload. It commonly contains timestamp and other resource-specific sections.
- data.timestamp: ISO-8601 string with timezone offset (e.g., +00:00). Use this to understand data recency and for cache expiration decisions.
- meta.request_id: String. Useful for logging, tracing, and support tickets.
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
- Set the endpoint to /api/v1/disruptions with type=wildfire and your target port (e.g., USLAX).
- 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).
- Parse the JSON and first check success. If false (or missing), log meta.request_id and halt.
- Use data.timestamp to align caching and freshness. It’s ISO-8601 with timezone info.
- 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
- Authentication and quotas
- Auth: header X-API-Key: YOUR_API_KEY. Guest without key: 100 requests/day per IP.
- If you exceed the guest limit, expect non-2xx or unsuccessful responses. Back off and add your API key.
- Response envelope
- Always check success before trusting data.
- Log meta.request_id on errors; it’s required for concise debugging with support.
- Timestamps and timezone
- data.timestamp is ISO-8601 with a timezone (e.g., 2026-10-11T00:00:19+00:00). Treat it as authoritative when deciding freshness.
- Normalize to UTC in your storage; include the original offset in logs for audits.
- Caching strategy
- For wildfire disruptions, cache conservatively (e.g., 5–10 minutes) unless your UI requires stricter freshness.
- Invalidate cache on changes in data.timestamp or when success becomes false, to avoid serving stale disruptions.
- Port congestion caveat
- Port congestion is IMF PortWatch, lagged ~6-7 days, 7-day avg vs 90-day baseline — not live AIS.
- Do not present congestion as live wait time; annotate any UI with the lag.
- Content boundaries
- Natural hazards only (GDACS/USGS/NOAA). Do not invent an event or cover strikes/canals.
- Do not quote a freight-rates USD fare as today’s price.
Testing your integration with USLAX
Start with a fixed port code (USLAX) to simplify logging and comparisons across environments. Keep a trace of:
- Full request URL with query parameters.
- HTTP status code and up to the first 1–2 KB of the response body for non-2xx cases.
- Parsed success, data.timestamp, and meta.request_id.
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
- Idempotency: Store the most recent disruptions snapshot keyed by port code and data.timestamp. If you receive the same timestamp twice, skip downstream notifications.
- Retry/backoff: On transient network errors (timeouts, 502/503), retry with exponential backoff and jitter. On 4xx auth errors, do not retry blindly.
- Monitoring: Alert when success !== true or when the shape of data changes significantly (missing timestamp, empty object where you expect content).
- Resilience: Treat any unrecognized fields as additive. Only depend on documented or observed-stable keys after verifying repeatedly in staging.
Security and key management
- Do not embed YOUR_API_KEY in client-side code or public repositories.
- Store the key in server-side secrets or environment variables and inject it into your request headers at runtime.
- Rotate keys periodically and monitor usage. If you see unexplained spikes (e.g., hitting guest caps), investigate IPs and tighten controls.
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.