HomeBlog

Tutorial

How to Add Logistics Intelligence to Your SaaS in 30 Minutes

March 16, 2026 · 8 min read · By FreightPulse Engineering

You're building a supply chain SaaS. Users want rates and port context inside your product. Aggregating ten vendor APIs is a long project. FreightPulse is a smaller surface: EIA fuel, US FTL, PortWatch activity, FMCSA lookup — one key.

This tutorial wires those live endpoints. It does not add a disruption news feed or a global ocean index; those are not in v1.

What You'll Build

Minute 0-5: Get Your API Key

Register at freightpulsehq.com/register. Free tier: 100 API calls/month. No credit card.

Copy the key from the dashboard:

export FREIGHTPULSE_API_KEY="fp_live_xxxxxxxxxxxx"

Minute 5-15: Backend Wrapper

// services/logistics.js
const API_BASE = 'https://freightpulsehq.com/api/v1';
const API_KEY = process.env.FREIGHTPULSE_API_KEY;

const headers = {
  'X-API-Key': API_KEY,
  'Accept': 'application/json'
};

export async function getFreightRates(originZip, destinationZip) {
  const params = new URLSearchParams({
    mode: 'trucking',
    origin_zip: originZip,
    destination_zip: destinationZip,
  });
  const res = await fetch(`${API_BASE}/freight-rates?${params}`, { headers });
  if (!res.ok) throw new Error(`FreightPulse API error: ${res.status}`);
  return res.json();
}

export async function getPortCongestion(locode) {
  const params = new URLSearchParams({ port: locode });
  const res = await fetch(`${API_BASE}/port-congestion?${params}`, { headers });
  if (!res.ok) throw new Error(`FreightPulse API error: ${res.status}`);
  return res.json();
}

Minute 15-20: App Routes

router.get('/api/logistics/rates', async (req, res) => {
  const { origin_zip, destination_zip } = req.query;
  const data = await getFreightRates(origin_zip, destination_zip);
  res.json(data);
});

router.get('/api/logistics/congestion/:locode', async (req, res) => {
  const data = await getPortCongestion(req.params.locode);
  res.json(data);
});

Cache and available

Warp quotes are cached ~30 minutes on our side. Still cache in your app. If data.available === false, show the note — do not read price_usd.

Minute 20-28: A Rate Card

function FreightRateCard({ originZip, destinationZip }) {
  const [body, setBody] = useState(null);

  useEffect(() => {
    const q = new URLSearchParams({
      origin_zip: originZip,
      destination_zip: destinationZip,
    });
    fetch(`/api/logistics/rates?${q}`)
      .then(r => r.json())
      .then(setBody);
  }, [originZip, destinationZip]);

  if (!body) return <Skeleton />;
  if (body.data?.available === false) {
    return <p>{body.data.note}</p>;
  }

  return (
    <div className="rate-card">
      <h3>FTL {originZip} → {destinationZip}</h3>
      <div className="rate-value">${body.data.price_usd}</div>
      <span>{body.data.transit_days} days · {body.data.service}</span>
    </div>
  );
}

Minute 28-30: Production Habits

  1. Degrade — never crash the dashboard if FreightPulse is down
  2. Loading states — PortWatch country queries can take tens of seconds; prefer port=USLAX
  3. Error boundaries — isolate the logistics widgets

What Not to Build Yet

Cost

Free 100 calls, Basic $49 / 1,000, Pro $99 / 10,000. Shared quota across endpoints.

Add Logistics Data to Your SaaS

EIA fuel, US FTL, port activity, FMCSA lookup. Start free.

Get Your API Key →

Resources