Agent skill

FourKites Webhooks Skill

Receive and authenticate FourKites webhooks (callbacks). Use when setting up a FourKites callback endpoint, verifying HTTP Basic auth on FourKites requests, debugging 401s, or handling MessageType values like LOAD_CREATION, TRACKING_UPDATE, STOP_ARRIVAL, STOP_DEPARTURE and STOP_ETA_UPDATED.

Install this skill

npx skills add hookdeck/webhook-skills --skill fourkites-webhooks


FourKites (supply chain visibility) POSTs a JSON callback to your URL when something happens to a load: it is created, a tracking update arrives, a truck arrives at or leaves a stop, an ETA changes, a stop is completed. The message kind is the MessageType field in the body.

Callbacks are not signed. FourKites supports three authentication methods, chosen when you subscribe: Basic Auth, API Key / Auth Header, or OAuth2 (client credentials). This skill covers HTTP Basic auth, which is what Hookdeck's FourKites source verifies. "Standard Webhooks" is FourKites' licensed product name; it is not the standardwebhooks.com signature spec.

When to Use This Skill

  • How do I receive FourKites webhooks / callbacks?
  • How do I authenticate FourKites requests with Basic auth?
  • Does FourKites sign webhook payloads? (No: use the shared credential)
  • How do I handle LOAD_CREATION, TRACKING_UPDATE, STOP_ARRIVAL or STOP_ETA_UPDATED?
  • Why does my FourKites webhook endpoint return 401?

Verification (core)

const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
const safeEqual = (a, b) =>
  crypto.timingSafeEqual(
    crypto.createHash('sha256').update(a).digest(),
    crypto.createHash('sha256').update(b).digest()
  );

function verifyFourKitesRequest(headers, user = process.env.FOURKITES_WEBHOOK_USERNAME,
                                pass = process.env.FOURKITES_WEBHOOK_PASSWORD) {
  if (!user || !pass) return false;                       // never accept when unconfigured
  const m = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(headers['authorization'] || '');  // scheme is case-insensitive
  if (!m) return false;
  const decoded = Buffer.from(m[1], 'base64').toString('utf8');
  const i = decoded.indexOf(':');                          // split on the FIRST colon
  if (i < 0) return false;
  const userOk = safeEqual(decoded.slice(0, i), user);     // evaluate both, no short-circuit
  const passOk = safeEqual(decoded.slice(i + 1), pass);
  return userOk && passOk;
}
  • Header: Authorization: Basic base64(username:password). Return 401 for a missing or malformed header or a mismatch, 400 for a body that isn't a JSON object, 200 once handled.
  • The credentials must arrive on the first request. FourKites' docs don't say whether Basic credentials are sent preemptively. A 401 + WWW-Authenticate challenge flow won't work through Hookdeck, which verifies the request as received.
  • A static shared credential authenticates the sender, not the body, and gives no replay protection (no signature, no timestamp). Anyone who captures a request can resend it. Use HTTPS only, make handlers idempotent, and rotate the credential if it leaks.
  • Python: hmac.compare_digest on bytes (encode both sides; str raises on non-ASCII).
  • Read the body raw (express.raw({ type: '*/*' })) and authenticate before parsing it.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Types

The body's MessageType field selects the event. Every key is present on every message.

MessageTypeSent When
LOAD_CREATIONFourKites successfully creates a load (carries FourKitesLoadId)
LOCATION_UPDATEA location update is recorded for a load
TRACKING_UPDATEKey tracking updates are made to the load (Status, Message)
STOP_ETA_UPDATEDA stop's ETA changes
STOP_ARRIVALThe truck arrives at a stop
STOP_DEPARTUREThe truck departs a stop
STOP_AUTO_COMPLETEDA stop is completed automatically
MANUALLY_DELIVEREDA load is manually marked delivered
MANUALLY_PICKED_UPA load is manually marked picked up
STOP_APPOINTMENT_RESCHEDULEDA stop appointment is rescheduled
STOP_AMENDA stop is amended
LOAD_DELETEDA load is deleted

More messages exist for orders, documents and facilities; see the FourKites API reference.

Environment Variables

FOURKITES_WEBHOOK_USERNAME=your-username   # supplied to FourKites when subscribing
FOURKITES_WEBHOOK_PASSWORD=your-password

Local Development

FourKites can't reach localhost. Tunnel with the Hookdeck CLI (no account required):

npx hookdeck-cli listen 3000 fourkites --path /webhooks/fourkites

Give FourKites the printed URL and the Basic credentials.

Resources


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 3, 2026

View on GitHub →