Logistics teams don’t lose sleep over “happy path” shipments. They lose it when storms materialize over a port of discharge, when a carrier’s safety rating changes mid-quarter, or when diesel prices spike the week you bid a strategic lane. Those are exception moments—the ones that break SLAs and erode margins. The fastest way to resolve exceptions is to surface them quickly and route them to the right humans or services with full context. This post shows how to do that by pairing event-driven design with FreightPulse’s consolidated logistics intelligence, so your operations can act in minutes, not days.
The old pattern—checking half a dozen portals, exporting CSVs, paying for yet another AIS feed just to monitor congestion, and stitching together data in a spreadsheet—can’t keep up with live freight. Developers need reliable signals they can automate against: whether a cyclone is approaching an inbound vessel’s port, whether FTL rates have shifted enough to re-route, whether a carrier is actually active and safe, whether fuel updates justify a mid-cycle surcharge tweak. FreightPulse provides those signals through one REST API; in this article, I’ll show how to convert them into webhook-driven exception workflows that push the right alert to the right channel, complete with remediation links and the next best action.
We’ll cover a practical, production-minded approach: which FreightPulse endpoints to poll on schedules appropriate to their data cadences, how to normalize and enrich events into a domain model that your operations team understands (“PortCongestionAlert”, “CarrierRiskChange”, “FuelSurchargeBreach”, “SevereWeatherProximity”), and how to fan out notifications via your webhook dispatcher to incident bots, TMS webhooks, or a custom Slack/Teams integration. We’ll include cURL requests, complete JSON examples, and code patterns you can adapt for your stack.
Why FreightPulse
Event-driven exception handling is only as good as the signals you ingest. FreightPulse consolidates critical transportation signals—live US FTL quotes, national and PADD-level fuel prices, port activity from IMF PortWatch, FMCSA/FMC carrier registries, and natural-disruption alerts—behind one consistent response shape. That means one schema to validate, one error model to catch, and one approach to retries and observability. Concretely, you benefit in four ways:
- Single integration, multi-domain coverage. Replace scattered feeds for EIA fuel, FMCSA/FMC carrier lookups, Warp truckload quotes, IMF PortWatch, and GDACS/USGS/NOAA alerts with one endpoint family. Your webhook engine ingests from a single base URL and forwards normalized events to downstream apps—no more credential sprawl or field mapping gymnastics across five vendors.
- Aligned data for decisioning. FreightPulse brings live FTL quotes and national diesel time series into the same JSON paradigm. That makes it trivial to codify playbooks like “if spot rises 15% week-over-week and FTL exceeds contract by 12% on lane NY–LA, switch to alternative pickup windows or consolidate shipments.”
- Operator-first signals. Access carrier facts that matter in the last mile—DOT number, safety rating, and driver counts—alongside disruption alerts that operators can act on (e.g., “Cyclone within 300km of USLAX” or “Severe weather near ORD”). Deliver fewer, richer alerts, each with a concrete next step: postpone pickup, use an alternate depot, or blocklist a carrier pending review.
- Frictionless exploration and uniform responses. All endpoints share a predictable JSON envelope with “success,” “data,” and optional “error” fields. That uniformity simplifies middleware, observability, dead-letter queues, and alert deduplication—especially important when building webhook-forwarding services that must be resilient to transient errors.
Quick Start
The FreightPulse REST API base URL is:
https://freightpulsehq.com/api/v1
Each response uses a consistent shape:
{
"success": true,
"data": { ... }
// or, if success=false:
// "error": "Human-readable message."
}
Here’s a first request to retrieve national and PADD-level fuel prices. You can run this from your CI agent, a serverless function, or a scheduled job that feeds a webhook dispatcher.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/fuel-prices"
Example response, which we’ll later translate into webhook-ready events when thresholds are crossed:
{
"success": true,
"data": {
"timestamp": "2026-07-30T12:00:00Z",
"source": "EIA (U.S. Energy Information Administration)",
"currency": "USD",
"unit": "gallon",
"data": {
"diesel": {
"national_average": 3.847,
"change_week": -0.023,
"change_percent": -0.6,
"regions": {
"east_coast": 3.912,
"midwest": 3.756,
"gulf_coast": 3.623,
"rocky_mountain": 3.891,
"west_coast": 4.456,
"california": 4.892
},
"historical": {
"30d_avg": 3.82,
"90d_avg": 3.75,
"yoy_change_percent": -8.2
}
},
"gasoline": {
"national_average": 3.156,
"historical": {
"30d_avg": 3.1,
"90d_avg": 3.05,
"yoy_change_percent": 1.1
}
}
}
}
}
Key fields you’ll typically use for exception workflows:
- data.data.diesel.national_average — base for fuel-surcharge recalculations.
- data.data.diesel.change_percent — a trigger for breach alerts (e.g., threshold of +3% WoW).
- data.data.diesel.regions — regional overrides in tariff models.
- data.data.diesel.historical — supports trend alerts and anomaly detection.
This single response can power alerts like “Fuel surcharge needs update” or “Rocky Mountain PADD diverges from national by > 10%.”
Core Endpoints
For event-driven exception workflows, you typically poll several endpoints on tailored cadences, translate deltas into domain events, and push to downstream systems via webhooks. Below are the core endpoints that generate actionable logistics signals. We’ll show cURL requests, complete JSON responses, and how to interpret key fields.
1) Fuel Prices — GET /fuel-prices
Purpose: Fetch national and PADD-region diesel/gasoline prices with weekly change and short- and mid-term historical averages. This supports surcharge recalculations, cost-to-serve monitoring, and budget variance alerts.
Key params: none.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/fuel-prices"
Response (complete example shown earlier) has:
- timestamp — the data timestamp; use it to deduplicate events and maintain idempotency.
- data.diesel.national_average — the primary benchmark for surcharges.
- data.diesel.change_week and change_percent — ready-made week-over-week triggers.
- data.diesel.regions — granular adjustments for PADD-level operations.
- data.diesel.historical — averages for smoothing, alert dampening, or graphs.
Event design tip: Persist the last “effective” price set your TMS used and compare each poll. If the absolute delta or percent delta exceeds your configured threshold, emit FuelSurchargeBreach with a payload containing national and relevant PADD values plus the calculated suggested surcharge.
2) Freight Rates — GET /freight-rates
Purpose: Obtain live quotes for US FTL trucking (via Warp) and limited ocean/air into US ZIP codes from Asian origins. Use this for spot rate validation, exception routing when contract carriers reject tenders, and re-quote workflows when disruptions or fuel shifts impact transit costs.
Key params (trucking): mode=trucking, origin_zip, destination_zip. Optional pickup_date, qty, total_weight_lb.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/freight-rates?mode=trucking&origin_zip=10001&destination_zip=90210"
Example response:
{
"success": true,
"data": {
"mode": "trucking",
"service": "FTL (53' dry van)",
"source": "Warp",
"price_usd": 7207.92,
"transit_days": 4,
"pickup_date": "2026-08-24",
"delivery_date": "2026-08-28"
}
}
Interpretation:
- data.price_usd — the actionable quote; compare against your contract rate to determine exception severity and whether to re-tender.
- data.transit_days — use to recompute ETA when re-routing. Pair with disruptions to preemptively re-quote lanes.
- data.pickup_date / data.delivery_date — anchor your promise date updates and alert text.
Event design tip: For shipments that fall outside contract windows or face capacity constraints, poll /freight-rates for the affected lanes and emit a SpotRateDeviation event when the quote is X% over contract. Include your shipment ID, affected SKUs, and an action URL that deep-links to a one-click re-tender flow.
3) Port Congestion — GET /port-congestion
Purpose: Approximate congestion conditions at major global ports using IMF PortWatch (AIS-derived) portcall averages. This informs ETA buffers, re-routing decisions, and customer communications. Important: this signal is lagged by ~6–7 days and represents a 7-day average vs a 90-day baseline. It is not a live AIS wait-time tracker.
Key params: at least one of port (name or LOCODE like USLAX), country, or region. Optional congestion=low|moderate|high filter.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/port-congestion?port=USLAX"
Example response:
{
"success": true,
"data": {
"results": [
{
"port": "Los Angeles-Long Beach",
"locode": "US LAX",
"country": "United States",
"congestion": "moderate",
"as_of": "2026-08-14",
"metrics": {
"recent_avg_portcalls_per_day": 8.7,
"baseline_avg_portcalls_per_day": 10.2,
"ratio_vs_baseline": 0.85
}
}
]
}
}
Interpretation:
- data.results[].congestion — qualitative tag for quick alert logic or color-coding dashboards.
- as_of — the date the 7-day average represents; only trigger events if you have not already processed this date.
- metrics.ratio_vs_baseline — normalized indicator; e.g., < 0.8 often suggests activity below baseline (possible congestion or reduced throughput).
Event design tip: Build a PortCongestionTrend event weekly. If ratio_vs_baseline drops below a threshold or flips category (e.g., from low to moderate), emit an alert with recommended buffer days for inbound shipments targeting that port.
4) Carriers — GET /carriers
Purpose: Verify US trucking carriers (FMCSA SAFER) or ocean NVOCC/OTI entities (FMC directory). Use for onboarding, re-audits, exception handling after incidents, or compliance-driven workflows.
Key params: q (required), type=trucking|ocean|air (air returns available:false).
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/carriers?q=54283"
Example response:
{
"success": true,
"data": {
"type": "trucking",
"query": "54283",
"results": [
{
"dot_number": 54283,
"legal_name": "SWIFT TRANSPORTATION COMPANY OF ARIZONA LLC",
"status": "active",
"safety_rating": "S",
"drivers": 12883,
"address": {
"city": "Phoenix",
"state": "AZ",
"country": "US"
}
}
]
}
}
Interpretation:
- status — use to blocklist or warn users if not “active.”
- safety_rating — map to internal risk categories; trigger CarrierRiskChange if a rating changes.
- drivers — rough proxy for scale/capacity; can influence routing heuristics.
Event design tip: Run nightly re-verification for key carriers. If status != active or the safety rating changes from your stored baseline, emit a CarrierRiskChange webhook to procurement and ops channels, including the carrier’s DOT number and a proposed mitigation step (e.g., secondary tender route).
5) Disruptions — GET /disruptions
Purpose: Detect active natural-hazard disruptions (GDACS, USGS, NOAA/NWS). These are precisely the externalities that derail schedules—cyclones, earthquakes, floods, volcanoes, drought, wildfire, and severe weather. Filter by country or by proximity to a target port.
Key params: type (cyclone|earthquake|flood|volcano|drought|wildfire|severe_weather), severity (low|moderate|high), country, port (with a proximity filter: 300km; 100km for US weather). Combine as needed.
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/disruptions?port=USLAX&severity=high"
Example response:
{
"success": true,
"data": {
"results": [
{
"id": "gdacs:TC:1001305",
"type": "cyclone",
"severity": "moderate",
"title": "Tropical Cyclone SAUDEL-26",
"country": "Japan",
"starts_at": "2026-08-18T12:00:00+00:00",
"source": "GDACS"
}
]
}
}
Interpretation:
- type / severity — primary routing keys for alerting. Severity often maps to playbooks: hold-at-origin, reroute, or notify consignee.
- id — stable identifier for deduplication; store and skip if already processed.
- starts_at — schedule pre-emptive actions before the event’s start.
Event design tip: A scheduled task runs every 30 minutes to scan disruptions near your key ports. When severity >= configured threshold, emit DisruptionProximityAlert with shipment IDs impacted (join by planned port) and next steps.
6) Historical Series — GET /historical
Purpose: Pull weekly national fuel-price series or daily port-congestion series for curated major ports. Use this to power thresholds based on moving averages, visualize trends inside your incident console, or compute seasonality-adjusted anomaly alerts that are less noisy than single-point thresholds.
Key params: metric (fuel_price_diesel_national, fuel_price_gasoline_national, or port_congestion:<portid>), period (30d|90d|1y).
curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/historical?metric=fuel_price_diesel_national&period=30d"
Example response:
{
"success": true,
"data": {
"metric": "fuel_price_diesel_national",
"period": "30d",
"series": [
{ "date": "2026-07-27", "value": 5.257 },
{ "date": "2026-08-03", "value": 5.343 }
]
}
}
Interpretation:
- series — time-indexed values ready for moving averages or visualization. Use 30d/90d to dampen noise in your alerts.
- metric — use as a routing key to index your historical cache and to label dashboards.
Event design tip: Compute a 4-week rolling average vs latest. If deviation exceeds Z-score thresholds, emit FuelTrendAnomaly with context (Z-score, latest value, rolling mean).
Designing Event-Driven Exception Workflows with a Webhook Dispatcher
FreightPulse provides the signals. Your job is to convert them into domain events that operations trust, with minimal noise and maximum context. A pragmatic way to do this is to run scheduled fetchers per endpoint, compute deltas vs your last-known baselines, and post webhook payloads to downstream systems (your TMS, internal incident bot, or BI pipeline). Below is a reference architecture and implementation patterns you can adapt.
- Scheduler: Per-endpoint cadence (e.g., disruptions every 15–30 minutes; freight rates on-demand for exception queues; fuel weekly; port congestion weekly; carriers nightly). Use cron, a CI scheduler, or serverless timers.
- Fetcher: Lightweight workers that call FreightPulse, handle pagination or filters, and normalize data to your internal event contracts.
- State store: Save last-processed timestamps, hashes, or identifiers (e.g., disruptions.id, congestion.as_of, fuel.timestamp) to ensure idempotency and deduplication.
- Decision engine: Apply threshold logic and compute recommended actions (e.g., “add two transit days,” “re-quote this lane,” “blocklist carrier,” “update fuel surcharge to X%”).
- Webhook dispatcher: Post alerts to subscribed endpoints. Retries with exponential backoff, circuit breakers, and a dead-letter queue for failed deliveries.
- Observability: Structured logs keyed by event ID and FreightPulse response timestamps; metrics per endpoint (success ratio, p95 latency, delta counts); traces for end-to-end delivery.
Here is a minimal Node.js/Express webhook receiver you might run in your downstream systems for local testing:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhooks/logistics', (req, res) => {
const event = req.body;
console.log('Received event:', event.type, 'id:', event.id);
// TODO: route to incident bot, TMS update, or analytics
res.status(200).send({ received: true });
});
app.listen(3000, () => console.log('Webhook listener on :3000'));
And a simple dispatcher example in JavaScript that would run inside your fetcher after detecting a meaningful delta:
async function postWebhook(eventPayload) {
const resp = await fetch('https://example.com/webhooks/logistics', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(eventPayload),
});
if (!resp.ok) {
// Implement retries/backoff and push to DLQ if needed
throw new Error(`Webhook delivery failed: ${resp.status}`);
}
}
Best practices:
- Idempotency: Include a deterministic event.id (e.g., hash of endpoint+entity+as_of or the disruption id) and time buckets, so downstream can ignore duplicates.
- Backoff and circuit breakers: If a downstream endpoint returns 5xx, pause deliveries to that subscriber until a health check passes.
- Payload hygiene: Include both raw FreightPulse data and your computed fields (e.g., “recommended_buffer_days”, “percent_delta”, “z_score”). This improves operator trust.
- Security: Sign outbound webhooks with HMAC headers. Receivers verify signatures before processing.
- Governance: Tag each event with “source=freightpulse” and your internal “app” and “team” labels for audit trails.
End-to-End Examples With Complete JSON Payloads
A) FuelSurchargeBreach event example
Polling /fuel-prices yields a week-over-week change beyond a 2% threshold. You compute a recommended surcharge and push a webhook event for immediate review.
{
"id": "evt_fuel_2026-07-30",
"type": "FuelSurchargeBreach",
"occurred_at": "2026-07-30T12:00:00Z",
"source": "freightpulse",
"payload": {
"diesel": {
"national_average": 3.847,
"change_week": -0.023,
"change_percent": -0.6,
"regions": {
"east_coast": 3.912,
"midwest": 3.756,
"gulf_coast": 3.623,
"rocky_mountain": 3.891,
"west_coast": 4.456,
"california": 4.892
},
"historical": {
"30d_avg": 3.82,
"90d_avg": 3.75,
"yoy_change_percent": -8.2
}
},
"surcharge_policy": {
"baseline_index": "EIA_diesel_national",
"threshold_percent": 2.0,
"previous_applied": 3.80,
"recommended_new": 3.85,
"justification": "Delta vs previous_applied > threshold"
},
"links": {
"review_url": "https://ops.example.com/surcharge/review?date=2026-07-30"
}
}
}
Downstream systems can auto-open a ticket with the recommended value and historical justification, speeding approvals.
B) PortCongestionTrend event example
The Los Angeles–Long Beach port ratio_vs_baseline dips below 0.85 compared to last week. You emit a trend event with remediation guidance.
{
"id": "evt_congestion_USLAX_2026-08-14",
"type": "PortCongestionTrend",
"occurred_at": "2026-08-14T00:00:00Z",
"source": "freightpulse",
"payload": {
"port": "Los Angeles-Long Beach",
"locode": "US LAX",
"country": "United States",
"as_of": "2026-08-14",
"congestion": "moderate",
"metrics": {
"recent_avg_portcalls_per_day": 8.7,
"baseline_avg_portcalls_per_day": 10.2,
"ratio_vs_baseline": 0.85
},
"policy": {
"threshold_ratio": 0.9,
"recommended_buffer_days": 2
},
"impacted_shipments": [
{ "id": "SH12345", "eta_port": "2026-08-21" },
{ "id": "SH19876", "eta_port": "2026-08-22" }
],
"links": {
"dashboard": "https://ops.example.com/ports/USLAX?as_of=2026-08-14"
}
}
}
Because port-congestion is a lagged approximation, always present “as_of” clearly and pair it with buffer guidance, not hard ETAs.
C) DisruptionProximityAlert event example
A high-severity disruption appears within range of a target port. You correlate shipments and push a consolidated alert:
{
"id": "evt_disruption_USLAX_gdacs:TC:1001305",
"type": "DisruptionProximityAlert",
"occurred_at": "2026-08-18T12:00:00Z",
"source": "freightpulse",
"payload": {
"disruption": {
"id": "gdacs:TC:1001305",
"type": "cyclone",
"severity": "moderate",
"title": "Tropical Cyclone SAUDEL-26",
"country": "Japan",
"starts_at": "2026-08-18T12:00:00+00:00"
},
"near_port": "USLAX",
"proximity_km": 300,
"impacted_shipments": [
{ "id": "SH77654", "milestone": "approaching_port" },
{ "id": "SH88901", "milestone": "loaded_on_vessel" }
],
"next_best_actions": [
"Evaluate alternate discharge port for SH77654",
"Alert consignee about potential delay (template D-3)"
],
"links": {
"incident_playbook": "https://ops.example.com/playbooks/cyclone-US-ports"
}
}
}
Note how the downstream sees not just the hazard but the operational impact and a ready-made playbook link.
Building the Fetchers: cURL, JavaScript, and Python Patterns
While cURL is perfect for exploration, production fetchers need robust HTTP clients, retries, and structured logging. Below are two minimal patterns you can adapt and extend.
JavaScript (Node.js) polling pattern for disruptions
import fetch from 'node-fetch';
async function fetchDisruptionsNear(port) {
const url = `https://freightpulsehq.com/api/v1/disruptions?port=${encodeURIComponent(port)}&severity=high`;
const resp = await fetch(url, {
headers: {
'X-API-Key': process.env.FP_API_KEY
}
});
const json = await resp.json();
if (!json.success) {
throw new Error(`Disruptions fetch failed: ${json.error}`);
}
return json.data.results || [];
}
async function run() {
try {
const results = await fetchDisruptionsNear('USLAX');
for (const item of results) {
// Deduplicate by item.id
// Match to open shipments by port
// Compute next best actions, then dispatch webhook
console.log('High-severity disruption candidate:', item.id, item.title);
}
} catch (err) {
console.error('Worker error:', err);
}
}
run();
Python polling pattern for port congestion
import os
import requests
def get_port_congestion(port_code: str):
url = f"https://freightpulsehq.com/api/v1/port-congestion?port={port_code}"
headers = { "X-API-Key": os.getenv("FP_API_KEY") }
r = requests.get(url, headers=headers, timeout=20)
r.raise_for_status()
data = r.json()
if not data.get("success", False):
raise RuntimeError(f"API error: {data.get('error')}")
return data["data"]["results"]
def evaluate_and_alert(results):
for r in results:
ratio = r["metrics"]["ratio_vs_baseline"]
if ratio < 0.9:
event = {
"id": f"evt_congestion_{r['locode'].replace(' ', '')}_{r['as_of']}",
"type": "PortCongestionTrend",
"occurred_at": r["as_of"] + "T00:00:00Z",
"source": "freightpulse",
"payload": {
"port": r["port"],
"locode": r["locode"],
"as_of": r["as_of"],
"congestion": r["congestion"],
"metrics": r["metrics"],
"policy": {
"threshold_ratio": 0.9,
"recommended_buffer_days": 2
}
}
}
# POST event to your webhook bus here
print("Dispatching webhook:", event["id"])
if __name__ == "__main__":
res = get_port_congestion("USLAX")
evaluate_and_alert(res)
Production notes: wrap I/O in retries with jitter, add a small circuit breaker to pause calls if repeated upstream errors occur, and log the upstream “as_of” or “timestamp” with each event so you can align alerts to source freshness.
Error Handling, Observability, and Governance
FreightPulse uses a uniform error envelope with success=false and a human-readable error message. Your workers should branch on “success” before reading data. Additionally, HTTP status codes communicate authentication or parameter issues. Here’s how to structure resilient handling and governance controls:
- HTTP 401/403: Authentication or entitlement issue. Alert your platform team and pause the affected worker to avoid noise. Do not blindly retry without remediation.
- HTTP 422: Missing required parameter (e.g., q on /carriers). Treat as a code bug; log and fix.
- HTTP 429: Too many requests in a period. Back off with exponential delay and a jitter strategy; stagger schedules per endpoint to smooth load.
- Service health checks: Add a lightweight GET (e.g., /fuel-prices) canary in your readiness probe and an external ping to validate end-to-end path (FreightPulse → your fetcher → your dispatcher → webhook receiver).
- Structured logging: Always log the upstream “as_of”/“timestamp,” your computed threshold comparisons, and the final decision (“alert_emitted=true|false”).
- Audit trails: Attach metadata like team, service, environment, and version to every webhook payload. Persist outbound webhook headers and response codes for 90 days to enable incident retrospectives.
Below is a synthetic example of an upstream error you should expect and handle:
{
"success": false,
"error": "Missing required parameter: q"
}
Your worker should convert this into an internal HealthCheckFailed event for visibility in your on-call dashboards, not an operator-facing alert. Keep operator noise exceedingly low; exception workflows earn trust when they are precise and rare.
Real-World Use Cases
Here are concrete projects teams ship with FreightPulse data powering event-driven exception handling:
- Fuel-surcharge calculator and breach alerts. Poll /fuel-prices weekly and /historical for smoothing; when the national diesel average deviates beyond preset thresholds, emit FuelSurchargeBreach to finance and pricing bots with the recommended update and one-click approval.
- Port-congestion dashboard with weekly trend alerts. Combine /port-congestion with /historical for curated ports like Shanghai, Singapore, Rotterdam, and Los Angeles–Long Beach. When ratio_vs_baseline drops or congestion changes category, send PortCongestionTrend events that annotate the shipments currently routed to that port.
- Carrier vetting and continuous monitoring for a 3PL. Use /carriers during onboarding to verify DOT and safety rating; run nightly checks. If status flips or safety_rating degrades, emit CarrierRiskChange to procurement and update your TMS via webhook to pause tenders until reviewed.
- Disruption-aware shipment tracker. Poll /disruptions by port and severity, join to in-transit shipments, then emit DisruptionProximityAlert with next-best actions (e.g., re-quote via /freight-rates). This keeps operators ahead of weather and geophysical events instead of reacting after delays occur.
- Spot-rate guardrail for rejected tenders. When a carrier declines a load, fetch /freight-rates for that lane; if price_usd exceeds your ceiling, route to a senior operator via a webhook for manual override, or else auto-select the next carrier.
Complete Endpoint Coverage and Practical Notes
For reference, here’s a concise mapping from FreightPulse endpoints to exception-driven value:
- GET /fuel-prices — surcharge policies, regional adjustments, and finance guardrails.
- GET /freight-rates — live spot checks for FTL and selective ocean/air; exception re-quote flows.
- GET /port-congestion — context for buffer days and proactive communications; lagged approximation suitable for trend-based alerts, not minute-by-minute decisions.
- GET /carriers — compliance, onboarding, and risk events based on status/safety changes.
- GET /disruptions — time-critical risk near ports; natural hazards only (no strikes/geopolitical).
- GET /historical — smoothing and trend detection for anti-noise alerting and visual context.
Tips for each:
- Fuel and historical: Use rolling means and Z-scores to suppress false positives. Consider PADD overrides in surcharge formulas. Include the original “source” field in operator messages for transparency.
- Freight rates: Treat quotes as volatile; store both the numeric price_usd and the pickup/delivery dates with your event to anchor context in your audit logs.
- Port congestion: Emphasize “as_of” in every alert. Aim for weekly cadence. Use ratio_vs_baseline over raw portcalls to normalize seasonality.
- Carriers: Map safety_rating codes to your own risk levels, and gate tenders when ratings degrade. Always include dot_number in webhook payloads for easy cross-system joins.
- Disruptions: Maintain a set of “watched ports” by program or customer. Send different playbooks by type and severity, e.g., severe_weather triggers a different path than cyclone.
Putting It Together: A Minimal Exception Engine
Below is a minimal pseudo-implementation that ties together polling, decisioning, and webhook dispatch. Adapt to your stack and productionize by adding metrics, queues, and robust retries.
// Pseudo-code sketch
schedule('0 */1 * * *', scanDisruptionsNearPorts); // hourly
schedule('0 6 * * 1', updateFuelAndSurcharge); // weekly, Mon 06:00
schedule('0 7 * * 1', refreshPortCongestionTrends); // weekly, Mon 07:00
schedule('0 2 * * *', reverifyCoreCarriers); // nightly 02:00
async function scanDisruptionsNearPorts() {
for (const port of WATCHED_PORTS) {
const resp = await fp('/disruptions', { port, severity: 'high' });
for (const d of resp.results) {
if (!seen(d.id)) {
const impacted = correlateShipments(port);
const event = buildDisruptionEvent(d, port, impacted);
await dispatch(event);
remember(d.id);
}
}
}
}
async function updateFuelAndSurcharge() {
const fpResp = await fp('/fuel-prices');
const current = fpResp.data.data.diesel.national_average;
const previous = await getLastApplied();
if (breach(previous, current, 0.02)) {
const recommended = computeSurcharge(previous, current);
await dispatch(buildFuelBreachEvent(fpResp.data, recommended));
await setLastApplied(current);
}
}
async function refreshPortCongestionTrends() {
for (const port of KEY_PORTS) {
const res = await fp('/port-congestion', { port });
for (const r of res.results) {
if (!processed(r.locode, r.as_of) && r.metrics.ratio_vs_baseline < 0.9) {
const shipments = correlateInbound(r.locode);
await dispatch(buildPortTrendEvent(r, shipments));
markProcessed(r.locode, r.as_of);
}
}
}
}
async function reverifyCoreCarriers() {
for (const dot of CORE_CARRIERS) {
const res = await fp('/carriers', { q: dot });
const carrier = res.results[0];
const prev = await getCarrierBaseline(dot);
if (prev.safety_rating !== carrier.safety_rating || prev.status !== carrier.status) {
await dispatch(buildCarrierRiskEvent(carrier, prev));
await setCarrierBaseline(dot, carrier);
}
}
}
This pattern scales because every event derives from deterministic inputs: upstream timestamps/IDs, your stored baselines, and threshold policies. With thorough logging, you can always explain why an alert fired and replay it if needed.
FAQ
How often do FreightPulse fuel prices update?
Fuel data in FreightPulse reflects EIA’s cadence. You can safely schedule a weekly pull and rely on change_week and change_percent to drive surcharge or budget variance workflows. For nuanced analysis, pair with /historical to compute rolling averages that reduce noise.
Can I look up ocean carriers as well as trucking carriers?
Yes. The /carriers endpoint supports trucking (FMCSA SAFER) and ocean NVOCC/OTI lookups (FMC directory) via the type parameter. Air currently returns available:false, which you can treat as a signal to skip or downgrade your checks for air carriers.
Does the port congestion data reflect real-time vessel wait times?
No. FreightPulse’s port congestion metric is a lagged approximation based on a 7-day average of portcalls versus a 90-day baseline, with a typical 6–7 day data lag. It’s excellent for trend alerts and buffer policies, but not for minute-by-minute decisions.
How should I deduplicate disruption alerts?
Use the disruption id as a stable key and maintain a small cache of processed IDs. When you emit webhooks, include a deterministic event.id so downstream systems can ignore duplicates and ensure idempotent processing.
What’s the best way to correlate disruptions or congestion to shipments?
Join on planned port (by LOCODE) and milestone (e.g., “approaching_port” within N days), or use the discharge/loading port on the shipment’s leg. For trucking, map disruption country/region or weather advisories to last-mile ZIP clusters and compute proximity drives.
Conclusion + CTA
Exception moments define your logistics operation’s reputation. The difference between a frustrated consignee and a delighted one often comes down to minutes—the time it takes to detect a risk and route it to the right owner with a concrete next step. By consolidating fuel, rates, port activity, carrier verification, and natural-disruption alerts into one API, FreightPulse makes it straightforward to build a webhook-driven exception engine that’s fast, explainable, and trusted by operators.
Whether you are a freight forwarder building a congestion-aware ETA dashboard, a 3PL automating carrier vetting and re-quote flows, or a supply chain SaaS team delivering proactive incident bots, the patterns in this post will get you into production quickly. Start by wiring the core endpoints, add a small decision layer for thresholds and playbooks, and let your webhook dispatcher push clean, contextual alerts across your stack.
Explore the API and see how quickly you can turn real logistics signals into action. Visit FreightPulse to learn more, and Try FreightPulse for free to start building your event-driven exception workflows today.