Home → Blog

You need to programmatically detect cyclone-related weather disruptions for a given seaport and turn that into a reliable signal inside your freight or visibility workflow. By the end of this guide, you will call the FreightPulse “Cyclone Disruptions” lookup from PHP, parse the envelope, handle auth, and ship a production-safe integration that respects caching and data freshness constraints (e.g., port congestion lag). You will also get ready-to-copy code, cURL, and response examples.

Scope and outcome

This article focuses exclusively on Weather disruptions—specifically the “Cyclone Disruptions” lookup for a given port code. All examples, endpoints, and fields in this post come from FreightPulse and are scoped to weather hazards. You will:

Illustration: How to Get Cyclone Disruptions

Authentication, quotas, and the response envelope

FreightPulse uses header authentication and a simple JSON envelope you can depend on across weather categories. Keep these facts in mind as you wire your client:

Important: Do not quote a freight-rates USD fare as today’s price from this endpoint. Cyclone disruptions are weather signals, not live rate quotes.

Weather disruptions endpoint for cyclone signals

The cyclone-focused lookup uses a simple query. Replace the port parameter with your target UN/LOCODE or supported port code. Keep the auth header intact, and preserve the type filter to cyclone.

Official cURL (copy-paste):

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

Notes you should implement in your client:

PHP implementation: step-by-step

This is a PHP-first integration, with explicit choices around timeouts, headers, and JSON parsing. The example uses cURL, which is standard in most PHP environments.

1) Build a small client function

Use a dedicated function to encapsulate headers, query, and error handling. Keep the endpoint and the required query parameters explicit to avoid category drift.

<?php
function fetchCycloneDisruptions(string $apiKey, string $portCode): array {
$url = 'https://freightpulsehq.com/api/v1/disruptions?port=' . urlencode($portCode) . '&type=cyclone';

$ch = curl_init($url);
$headers = [
'Accept: application/json',
'X-API-Key: ' . $apiKey
];

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

$raw = curl_exec($ch);
$errNo = curl_errno($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($errNo !== 0) {
throw new RuntimeException('Network error (cURL errno=' . $errNo . ')');
}

if ($status < 200 || $status >= 300) {
throw new RuntimeException('HTTP error status=' . $status);
}

$json = json_decode($raw, true);
if (!is_array($json)) {
throw new RuntimeException('Invalid JSON');
}

if (!array_key_exists('success', $json) || $json['success'] !== true) {
// Envelope is defined as {"success":true,"data":{...}}; treat otherwise as an error.
throw new RuntimeException('API indicated unsuccessful response');
}

if (!array_key_exists('data', $json) || !is_array($json['data'])) {
throw new RuntimeException('Missing data envelope');
}

return $json; // Keep meta/request_id for observability if present.
}

// Example usage:
try {
$apiKey = 'YOUR_API_KEY';
$port = 'USLAX';
$response = fetchCycloneDisruptions($apiKey, $port);

// Access the envelope:
$success = $response['success'];
$data = $response['data'];
$meta = isset($response['meta']) ? $response['meta'] : null;

// Downstream: inspect $data according to your weather disruption fields.
// Always guard against fields being absent or null as schemas can evolve.
if ($meta && isset($meta['request_id'])) {
error_log('FreightPulse request_id=' . $meta['request_id']);
}

// Your business logic here (e.g., store $data for the port & show signals in UI).
print_r($data);

} catch (Throwable $e) {
// Production: map to your error handling infra (e.g., Sentry, Honeycomb, CloudWatch).
error_log('FreightPulse cyclone disruptions error: ' . $e->getMessage());
}

2) Time and timezone handling

When you work with weather disruptions or related metadata, treat timestamps as ISO-8601 with explicit offsets (e.g., +00:00 for UTC). Store them as UTC internally to keep comparisons and SLA windows predictable across regions.

3) Caching policy

Python quickstart (optional helper)

If your team also uses Python for data processing, here is a lightweight example that mirrors the same endpoint and envelope handling. Keep the header name and query string unchanged.

import os
import requests

def fetch_cyclone_disruptions(api_key: str, port_code: str) -> dict:
url = "https://freightpulsehq.com/api/v1/disruptions"
params = {"port": port_code, "type": "cyclone"}
headers = {"X-API-Key": api_key, "Accept": "application/json"}
r = requests.get(url, headers=headers, params=params, timeout=20)
r.raise_for_status()
payload = r.json()

if not isinstance(payload, dict) or payload.get("success") is not True:
raise RuntimeError("Unsuccessful response envelope")

data = payload.get("data", {})
meta = payload.get("meta", {})
# Use request_id for tracing
if "request_id" in meta:
print(f"request_id={meta['request_id']}")

return payload

if __name__ == "__main__":
api_key = "YOUR_API_KEY"
port = "USLAX"
result = fetch_cyclone_disruptions(api_key, port)
print(result.get("data", {}))

Field usage and guardrails

Across FreightPulse Weather endpoints, the top-level envelope is consistent: success (boolean), data (object), and optional meta (object). Treat unknown or missing fields as expected in evolving weather taxonomies. In your ingestion layer:

Official sample response and important notes

The following official sample block is provided as-is and demonstrates the envelope shape you should code against. Copy it verbatim if you are testing JSON parsing. Your cyclone disruptions response will follow the same envelope pattern.

{
"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"
}
}

What you will use operationally:

Additional JSON examples of the envelope

These examples illustrate the success/data/meta envelope shape you should code against for cyclone disruption lookups. They use only documented fields, allowing you to unit-test your parsing and error handling paths.

{
"success": true,
"data": {},
"meta": {
"request_id": "example-request-id-1"
}
}
{
"success": true,
"data": {},
"meta": {
"request_id": "example-request-id-2"
}
}

Operational guidance: freshness, units, and hazard scope

Implementers often lose time reconciling timeliness and measurement conventions. Save yourself cycles by adopting the following defaults from day one:

Testing strategy, retries, and monitoring

Follow a minimal but concrete regimen so your integration stays predictable under load and when network conditions degrade:

Putting it together in your application

Developers typically integrate cyclone weather disruptions in one of three patterns:

Start with a scheduled job if you serve a known list of ports. Trigger on-demand fallbacks only when a user drills into a previously uncached port to stay well within guest quotas or your allocated plan limits.

Reference: cURL to verify your environment

Use this exact command to validate your server’s egress, SSL bundle, and header propagation. Keep the URL and header names identical:

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

Troubleshooting checklist

FAQ

Q: Can I call the cyclone disruptions endpoint without an API key?
A: Yes, but as a guest you are limited to 100 requests/day per IP. For production, set X-API-Key: YOUR_API_KEY.

Q: Are the congestion signals live AIS wait times?
A: No. FreightPulse congestion uses IMF PortWatch and is lagged ~6–7 days (7-day average vs 90-day baseline). Treat it as delayed, not live.

Q: What hazard sources back the cyclone category?
A: Natural hazards are sourced from GDACS/USGS/NOAA. The endpoint is Weather-specific—do not conflate it with strikes or canal disruptions.

Q: How should I handle timestamps?
A: Expect ISO-8601 with timezone offset. Normalize to UTC internally to keep comparisons and windows consistent.

Q: Can I present a USD freight rate as today’s price based on this endpoint?
A: No. Do not quote a freight-rates USD fare as today’s price from this endpoint.

Ready to implement cyclone disruption lookups in your stack? Create an account and get an API key here: Register. For field-by-field details and additional Weather examples, see the Documentation.