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_ARRIVALorSTOP_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). Return401for a missing or malformed header or a mismatch,400for a body that isn't a JSON object,200once handled. - The credentials must arrive on the first request. FourKites' docs don't say whether Basic credentials are sent preemptively. A
401+WWW-Authenticatechallenge 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_digeston bytes (encode both sides;strraises 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.
| MessageType | Sent When |
|---|---|
LOAD_CREATION | FourKites successfully creates a load (carries FourKitesLoadId) |
LOCATION_UPDATE | A location update is recorded for a load |
TRACKING_UPDATE | Key tracking updates are made to the load (Status, Message) |
STOP_ETA_UPDATED | A stop's ETA changes |
STOP_ARRIVAL | The truck arrives at a stop |
STOP_DEPARTURE | The truck departs a stop |
STOP_AUTO_COMPLETED | A stop is completed automatically |
MANUALLY_DELIVERED | A load is manually marked delivered |
MANUALLY_PICKED_UP | A load is manually marked picked up |
STOP_ | A stop appointment is rescheduled |
STOP_AMEND | A stop is amended |
LOAD_DELETED | A 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
- references/overview.md - What FourKites callbacks are, events, retries
- references/setup.md - Subscribe a URL and choose Basic auth
- references/verification.md - Basic auth check details, gotchas, debugging 401s
- examples/ - Runnable Express, Next.js and FastAPI handlers with tests