Skip to main content

Webhooks

Subscribe to real-time events from the Freight Engine platform. Get notified instantly when loads are posted, bids received, shipments delivered, and more.

Supported Events

EventDescription
load.postedA new load has been posted to the marketplace
load.matchedA load has been matched with a carrier
load.picked_upCarrier has picked up the load
load.deliveredLoad has been delivered to destination
bid.receivedA new bid has been placed on a load
bid.acceptedA bid has been accepted by the shipper
pod.confirmedProof of delivery has been confirmed
payment.releasedPayment has been released to the carrier
invoice.generatedAn invoice has been generated

Payload Format

Every webhook delivery sends a JSON POST request with the following structure:

{
  "event": "load.posted",
  "payload": {
    "loadId": "abc123",
    "originCity": "Atlanta",
    "originState": "GA",
    "destCity": "Nashville",
    "destState": "TN",
    "equipmentType": "DRY_VAN",
    "rate": 2450.00,
    "pickupDate": "2026-04-12T08:00:00Z"
  },
  "timestamp": "2026-04-10T14:32:00.000Z",
  "deliveryId": "d4e5f6a7-b8c9-..."
}

Headers

X-Webhook-Signature: sha256=<hmac_hex_digest>
X-Webhook-Event: load.posted
X-Webhook-Delivery: d4e5f6a7-b8c9-...
Content-Type: application/json

Verifying Signatures

Every delivery includes an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this signature to ensure the request is authentic.

Node.js

import crypto from "crypto";

function verifyWebhook(body: string, signature: string, secret: string): boolean {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your handler:
app.post("/webhook", (req, res) => {
  const signature = req.headers["x-webhook-signature"];
  const rawBody = JSON.stringify(req.body);

  if (!verifyWebhook(rawBody, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: "Invalid signature" });
  }

  const { event, payload } = req.body;
  console.log(`Received ${event}`, payload);
  res.status(200).json({ received: true });
});

Python

import hmac
import hashlib
import json

def verify_webhook(body: str, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode("utf-8"),
        body.encode("utf-8"),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# In your Flask handler:
@app.route("/webhook", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Webhook-Signature", "")
    raw_body = request.get_data(as_text=True)

    if not verify_webhook(raw_body, signature, os.environ["WEBHOOK_SECRET"]):
        return jsonify({"error": "Invalid signature"}), 401

    data = request.get_json()
    print(f"Received {data['event']}", data["payload"])
    return jsonify({"received": True}), 200

Managing Endpoints

Register an Endpoint

POST /api/webhooks
Content-Type: application/json
Authorization: Bearer <token>

{
  "action": "register",
  "url": "https://your-app.com/webhook",
  "events": ["load.posted", "bid.received", "load.delivered"],
  "secret": "whsec_your_secret_key_here"
}

Remove an Endpoint

POST /api/webhooks
Content-Type: application/json
Authorization: Bearer <token>

{
  "action": "remove",
  "endpointId": "endpoint_abc123"
}

Send a Test Event

POST /api/webhooks
Content-Type: application/json
Authorization: Bearer <token>

{
  "action": "test",
  "endpointId": "endpoint_abc123"
}

List Endpoints

GET /api/webhooks
Authorization: Bearer <token>

View Delivery Log

GET /api/webhooks?endpointId=endpoint_abc123
Authorization: Bearer <token>

Retry Policy

Failed deliveries are retried up to 3 times with exponential backoff (2s, 4s).

Endpoints with 15+ failures in the last 24 hours are automatically disabled.

Your endpoint must respond with a 2xx status code within 10 seconds.

Freight Engine Developer Documentation

Ask LoadLadder AI

Instant answers about our platform

Try asking: