Home → Blog

Surprise detention and demurrage fees are the supply chain equivalent of an unplanned outage: they blow up budgets, wreck SLAs, and erode customer trust. Yet most teams still react after the fact—discovering a port slowdown or weather event only when a container misses its free time. The fix is not one more dashboard; it’s a programmable risk model that ingests the right operational signals ahead of time and triggers actions before charges accrue.

This post shows how to build automated detention and demurrage forecasting on top of a single, cohesive logistics data surface. With FreightPulse, your apps can combine lagged-yet-actionable port throughput changes, real-time natural-hazard alerts, live full-truckload (FTL) quotes, carrier verifications, and national fuel-price signals under one REST API. You’ll learn how to fuse these inputs into a practical risk score, what to automate (holds, pickups, drayage reschedules), and how to do it with a few HTTP calls and standard JSON—no fragile web scrapers or five vendor integrations stitched together with glue code.

If your job is freight forwarding, 3PL operations, enterprise logistics, or platform engineering for supply chain SaaS, this tutorial is written for you. We’ll walk step-by-step through endpoints that matter for detention/demurrage forecasting, cover common pitfalls, and provide code you can adapt in production.

Why FreightPulse

Forecasting detention and demurrage requires cross-signal context: port congestion trends to anticipate yard clogs, disruption alerts near ports to flag inclement weather and cyclones, live trucking quotes to price alternate dray or over-the-road options, verified carrier data to ensure credible plan B capacity, and fuel prices to adjust surcharges on urgent diversions. With most stacks this means five different vendors, inconsistent JSON, and a month of integration work. FreightPulse consolidates that into one composable API and a consistent response envelope.

Quick Start

All examples in this post use a single base URL and a shared JSON envelope for predictable error handling and logging. You can test endpoints directly from your terminal with cURL.

Base URL:


https://freightpulsehq.com/api/v1

First request: pull the current national diesel/gasoline signal to calibrate fuel-related surcharges on urgent diversions you may schedule to dodge demurrage.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/fuel-prices"
{
"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 use:

Core Endpoints for Detention and Demurrage Forecasting

In forecasting workflows, you’ll ingest several endpoints per shipment. Below we cover each relevant path, parameters, realistic sample responses, and how to interpret fields for operational decisions.

1) Port Congestion: GET /port-congestion

Purpose: Estimate yard and berth stress with a lag-aware ratio. FreightPulse approximates port activity as a 7-day average of port calls vs a 90-day baseline, derived from IMF PortWatch AIS data. This is not live AIS; treat it as a structural stress indicator to adjust free-time risk, container availability, and appointment lead times.

Common usage: Forecast demurrage risk windows for import containers by mapping congestion level to longer dwell expectation; trigger earlier drayage booking where congestion is moderate/high.

Key params:


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/port-congestion?port=USLAX"
{
"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
}
}
]
}
}

Field interpretation:

2) Disruptions: GET /disruptions

Purpose: Detect natural hazards near a specific port before they impact berthing, yard operations, gate hours, or inland legs. Filter by severity and type to reduce noise and drive alerts only when a disruption is operationally meaningful.

Common usage: If a cyclone or severe weather is near your discharge port, preemptively shorten ticket-to-trucker lead time, push notifications to consignees, and book alternate dray or transload to skip accruing demurrage.

Key params:


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/disruptions?port=USLAX&severity=high"
{
"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"
}
]
}
}

Field interpretation:

3) Historical series: GET /historical

Purpose: Build trend-aware models. For demurrage, combine port congestion history with your own historical dwell and free-time outcomes to learn which ratio thresholds cause fee spikes. For detention, absorb diesel trendlines and port activity into pickup appointment forecasts.

Key params:


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/historical?metric=port_congestion:USLAX&period=90d"
{
"success": true,
"data": {
"metric": "port_congestion:USLAX",
"period": "90d",
"series": [
{
"date": "2026-06-01",
"value": 0.89
},
{
"date": "2026-06-08",
"value": 0.86
}
]
}
}

Field interpretation:

4) Freight rates: GET /freight-rates

Purpose: Price alternates quickly. When your model raises demurrage risk, you want to simulate options—expedited dray to inland ramp, direct OTR to consignee, or a cross-dock and linehaul. Pull FTL price signals for US lanes, and limited ocean/air modes for Asian origins into US ZIPs, to quantify diversion costs against projected demurrage.

Key params (trucking):


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/freight-rates?mode=trucking&origin_zip=90744&destination_zip=85001&pickup_date=2026-08-24&total_weight_lb=42000"
{
"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"
}
}

Field interpretation:

5) Carriers: GET /carriers

Purpose: Verify carrier legitimacy and capabilities before committing to plan B. In detention/demurrage avoidance, speed is everything—but not at the expense of selecting an unsafe or inactive carrier. Query FMCSA SAFER records for US trucking or FMC directory for ocean NVOCC/OTI.

Key params:


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/carriers?q=54283"
{
"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"
}
}
]
}
}

Field interpretation:

6) Fuel prices: GET /fuel-prices

Purpose: Power your surcharge engine. When you fast-track a dray or over-the-road move to prevent demurrage, the fuel signal informs total landed cost, win-loss logic, and shipper communication.

No required params. Response example shown in Quick Start. A few practical implementation notes:

How the Pieces Fit: A Simple Demurrage Risk Model

A practical forecast blends lag-aware congestion, real-time hazards, historical trends, and price signals into a score that drives action. Here’s a blueprint:

This is simple to compute yet powerful in production, especially when you run it twice daily per inbound container and trigger workflows when thresholds are crossed.

End-to-End Example: Pull, Score, and Decide

Below is a minimal Python workflow that pulls multiple signals for a container discharging at Los Angeles-Long Beach, estimates risk, and calculates a diversion option. Adapt the heuristics to your tariff and historical dwell data.


import os
import requests
from datetime import date

BASE = "https://freightpulsehq.com/api/v1"
HEADERS = {"X-API-Key": os.getenv("FP_API_KEY", "")}

def get_json(path, params=None):
r = requests.get(f"{BASE}{path}", headers=HEADERS, params=params or {}, timeout=20)
j = r.json()
if not j.get("success"):
raise RuntimeError(j.get("error", "Unknown error"))
return j["data"]

# 1) Port congestion
pc = get_json("/port-congestion", {"port": "USLAX"})
pc_row = pc["results"][0]
ratio = pc_row["metrics"]["ratio_vs_baseline"]
cong = pc_row["congestion"]

# 2) Disruptions near port
dz = get_json("/disruptions", {"port": "USLAX", "severity": "high"})
hazard_count = len(dz["results"])

# 3) Diesel price (for surcharge)
fuel = get_json("/fuel-prices", {})
diesel = fuel["data"]["diesel"]["national_average"]

# 4) FTL diversion price from Wilmington, CA 90744 to Phoenix, AZ 85001
fr = get_json("/freight-rates", {
"mode": "trucking",
"origin_zip": "90744",
"destination_zip": "85001",
"pickup_date": date.today().isoformat(),
"total_weight_lb": 42000
})
price = fr["price_usd"]
transit_days = fr["transit_days"]

# Naive risk model
base = 0.1 if cong == "low" else 0.4 if cong == "moderate" else 0.7
haz_mult = 1.3 if hazard_count > 0 else 1.0
risk = min(1.0, base * haz_mult)

# Fuel surcharge (very simplified)
fuel_surcharge = 0.05 * price * (diesel / 3.5)

decision = {
"port_ratio": ratio,
"congestion": cong,
"hazards_near_port": hazard_count,
"risk_score": round(risk, 2),
"diversion_price_estimate": round(price + fuel_surcharge, 2),
"ftl_transit_days": transit_days
}
print(decision)

Error Handling, Retries, and Observability

Production forecasting hits multiple endpoints, so treat the pipeline as a distributed system. Standardize on FreightPulse’s response shape to implement cross-endpoint reliability and observability.

A sample error response to handle:

{
"success": false,
"error": "Missing required parameter: q"
}

Practical tip: Log endpoint, params hash, HTTP status, and the "error" string. In metrics, count success vs error by endpoint to spot integration regressions quickly.

Complete Endpoint Reference with Practical Notes

GET /fuel-prices

Returns national diesel/gasoline averages, regional breakdowns, weekly delta, and historical aggregates (30d/90d/YoY). Use national_average for simple surcharges, and regions for PADD-aware logic. A stable surcharge calms rate volatility in last-minute diversions to avoid demurrage.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/fuel-prices"

Important fields:

GET /freight-rates

Live US FTL quotes (via Warp) plus limited ocean/air into US from Asia. For demurrage avoidance, the most common task is quantifying OTR alternatives from the port to DC or transload. Always check for the { available: false } case when required params are missing.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/freight-rates?mode=trucking&origin_zip=10001&destination_zip=90210"
{
"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"
}
}

Use price_usd and transit_days directly in your “demurrage vs diversion” decision card.

GET /port-congestion

Returns a 7-day port-calls average vs 90-day baseline with a categorical congestion label. It’s a lagged approximation, not live AIS. Its value is in forecasting: when the ratio dips (or spikes), yards and berths follow with predictable lag. Build thresholds per port.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/port-congestion?port=USLAX&congestion=high"

Filter by congestion=high to find global hot spots your network planning team should preemptively route around.

GET /carriers

Trust but verify. Pull FMCSA SAFER data for US trucking carriers, and FMC NVOCC/OTI for ocean. When operations need to act in hours—not days—this query saves you from scrambling the wrong partner.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/carriers?type=ocean&q=EXPEDITORS"

Air lookups return available:false; build your UI to reflect that gracefully.

GET /disruptions

Consolidates GDACS, USGS, and NOAA/NWS natural hazard alerts. For detention/demurrage risk, the proximity-to-port filter is the secret weapon—signal only when a hazard is operationally relevant.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/disruptions?type=severe_weather&port=USNYC&severity=moderate"

GET /historical

Fetch weekly national fuel series or daily port congestion series for curated major ports. Train your forecasting thresholds or display rolling trends in a control tower UI so planners can see stress build-ups before invoices arrive.


curl -H "X-API-Key: YOUR_API_KEY" \
"https://freightpulsehq.com/api/v1/historical?metric=fuel_price_diesel_national&period=1y"

JavaScript Example: Build a Simple Risk Card in a Web App

The following snippet shows how to fetch congestion, disruptions, and rates in parallel for a port-to-DC scenario and render a compact decision card.


async function fp(path, params = {}) {
const url = new URL(`https://freightpulsehq.com/api/v1${path}`);
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
const res = await fetch(url.toString(), {
headers: { "X-API-Key": window.FP_API_KEY || "" }
});
const json = await res.json();
if (!json.success) throw new Error(json.error || "Error");
return json.data;
}

async function buildRiskCard() {
const [pc, dz, fr] = await Promise.all([
fp("/port-congestion", { port: "USLAX" }),
fp("/disruptions", { port: "USLAX", severity: "high" }),
fp("/freight-rates", {
mode: "trucking",
origin_zip: "90744",
destination_zip: "85001",
pickup_date: new Date().toISOString().slice(0, 10),
total_weight_lb: 42000
})
]);

const row = pc.results[0];
const ratio = row.metrics.ratio_vs_baseline;
const congestion = row.congestion;
const hazards = dz.results.length;
const price = fr.price_usd;
const etaDays = fr.transit_days;

const base = congestion === "low" ? 0.1 : congestion === "moderate" ? 0.4 : 0.7;
const risk = Math.min(1, base * (hazards > 0 ? 1.3 : 1.0));

return {
port: row.port,
ratio,
congestion,
hazards,
diversion: { price, etaDays },
risk: Number(risk.toFixed(2))
};
}

buildRiskCard().then(console.log).catch(console.error);

Performance Tips and Best Practices

Real-World Use Cases

FAQ

How often do FreightPulse fuel prices update?

Fuel prices are sourced from the EIA and exposed with weekly updates plus historical aggregates for 30/90 days and year-over-year. Treat them as stable inputs for surcharge models rather than minute-level signals; cache for an hour in production.

Can I look up ocean carriers as well as trucking carriers?

Yes. Use GET /carriers with type=ocean to query the FMC directory for NVOCC/OTI entities, and the default type=trucking for FMCSA SAFER records. Air lookups return available:false, so handle that case gracefully in your UI.

Does the port congestion data reflect real-time vessel wait times?

No. Port congestion is a lagged approximation derived from IMF PortWatch AIS data: a 7-day average of port calls compared to a 90-day baseline with a ~6–7 day lag. It’s designed as a structural stress indicator for forecasting—not as a live queue length.

Can I filter disruption alerts to only those near a specific port?

Yes. The /disruptions endpoint supports a port parameter that limits results by proximity (300 km globally, 100 km for US weather). This keeps alerts operationally relevant to your discharge or load port.

What’s the best way to compare demurrage risk against a diversion cost?

Blend /port-congestion and /disruptions into a risk score, estimate likely dwell extension, then price alternates with /freight-rates and a surcharge derived from /fuel-prices. Compare the total diversion estimate to your tariff-based demurrage projection and trigger a workflow if the delta is favorable.

Troubleshooting and Integration Notes

Sample combined happy-path response set you might persist per forecasting cycle:

{
"fuel_prices": {
"success": true,
"data": {
"timestamp": "2026-07-30T12:00:00Z",
"data": {
"diesel": { "national_average": 3.847 }
}
}
},
"congestion": {
"success": true,
"data": {
"results": [
{
"port": "Los Angeles-Long Beach",
"congestion": "moderate",
"metrics": { "ratio_vs_baseline": 0.85 }
}
]
}
},
"disruptions": {
"success": true,
"data": {
"results": []
}
},
"rates": {
"success": true,
"data": {
"mode": "trucking",
"price_usd": 7207.92,
"transit_days": 4
}
}
}

Security, Governance, and Operational Controls

Putting It All Together: From Zero to Production

In a typical rollout, teams start by integrating /port-congestion and /disruptions for 3–5 critical ports with the largest demurrage exposure. They build a simple threshold model and deliver alerts to a Slack channel. Next, they wire in /freight-rates to attach a diversion quote to each alert, and /fuel-prices to parameterize the surcharge. Finally, they build a control panel that shows risk bands per container and supports one-click booking—backed by /carriers checks—to preempt fees at scale.

By consolidating all core signals behind a single API, you reduce integration risk, speed up iteration cycles, and empower operators with a coherent, explainable model. And because the response envelope is consistent across endpoints, your reliability engineering efforts—retries, backoff, circuit breakers, and metrics—apply uniformly.

The result is not just fewer surprise invoices; it’s a calmer, more predictable operation where exception handling becomes a programmable workflow instead of an all-hands fire drill.

Conclusion + CTA

Detention and demurrage fees thrive in blind spots—when teams see congestion shifts and hazards too late, and when costing alternates takes longer than the free time you have left. The fastest fix is a programmable, risk-first approach built on top of unified logistics intelligence: congestion approximations for ports you care about, real-time hazard proximity, live FTL alternatives, verified carriers, and stable fuel signals to price decisions—all accessible in the same JSON schema.

With FreightPulse, developers can move from concept to production quickly: one REST surface, consistent responses, and endpoints purpose-built for forecasting and exception automation. Whether you are a forwarder, 3PL, enterprise supply chain team, or a platform vendor, you can instrument proactive workflows that turn potential penalties into predictable operations.

Start building your detention and demurrage forecaster today. Explore the endpoints, wire them into your TMS or control tower, and automate the decisions that matter most. Try FreightPulse for free.