| name | flexport-webhooks-events |
| description | Implement Flexport webhook event handling for shipment milestones, booking updates,
purchase order events, and invoice notifications.
Trigger: "flexport webhooks", "flexport events", "flexport milestones",
"flexport shipment tracking webhook".
|
| allowed-tools | Read, Write, Edit, Bash(npm:*), Bash(curl:*) |
| version | 1.6.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| tags | ["saas","logistics","flexport"] |
| compatibility | Designed for Claude Code |
Flexport Webhooks & Events
Overview
Flexport sends webhook notifications for shipment milestones, booking confirmations, PO updates, invoice events, and document availability. Webhooks are configured in Portal > Settings with a secret token for HMAC-SHA256 signature verification via the X-Hub-Signature header.
Webhook Event Types
| Category | Events | Use Case |
|---|
| Milestones | cargo_ready, departed, arrived, customs_cleared, delivered | Shipment tracking |
| Transit | estimated_departure, estimated_arrival, actual_departure | ETA updates |
| Bookings | booking_confirmed, booking_amended | Booking lifecycle |
| Purchase Orders | po_created, po_updated, po_archived | PO management |
| Invoices | invoice_created, freight_invoice_ready | Billing |
| Documents | document_uploaded, bill_of_lading_ready | Document management |
| Container | container_loaded, container_unloaded | Container tracking |
Instructions
Step 1: Create Webhook Endpoint in Flexport
Navigate to Portal > Settings > Webhooks > Add Endpoint:
- URL:
https://your-app.com/webhooks/flexport
- Secret: Generate a strong random string
- Events: Select event types to subscribe to
Step 2: Implement Webhook Handler
import crypto from 'crypto';
import express from 'express';
const app = express();
app.post('/webhooks/flexport', express.raw({ type: '*/*' }), async (req, res) => {
const signature = req.headers['x-hub-signature'] as string;
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.FLEXPORT_WEBHOOK_SECRET!)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
console.error('Invalid webhook signature');
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req..());
.();
{
(event);
res.().();
} (err) {
.(, err);
res.().();
}
});
() {
(event.) {
:
(event.);
;
:
(event.);
;
:
(event.);
;
:
(event.);
;
:
(event.);
;
:
.();
}
}
Step 3: Handle Shipment Milestones
async function handleMilestone(data: {
shipment_id: string;
milestone: string;
occurred_at: string;
location?: { name: string; country: string };
}) {
console.log(`Milestone: ${data.milestone} for ${data.shipment_id}`);
console.log(` At: ${data.occurred_at} | Location: ${data.location?.name}`);
await db.shipments.update({
where: { flexportId: data.shipment_id },
data: {
status: data.milestone,
lastMilestoneAt: new Date(data.occurred_at),
currentLocation: data.location?.name,
},
});
if (['departed', 'arrived', 'delivered'].includes(data.milestone)) {
await notifyStakeholders(data.shipment_id, data.milestone);
}
}
Step 4: Idempotent Processing
async function processWebhookIdempotently(event: any) {
const eventId = event.id || crypto.createHash('sha256')
.update(JSON.stringify(event)).digest('hex');
const exists = await db.webhookLog.findUnique({ where: { eventId } });
if (exists) {
console.log(`Duplicate webhook ${eventId}, skipping`);
return;
}
await db.$transaction([
db.webhookLog.create({ data: { eventId, type: event.type, processedAt: new Date() } }),
routeEvent(event),
]);
}
Error Handling
| Issue | Cause | Solution |
|---|
| 401 signature mismatch | Wrong secret or body parsing | Use express.raw(), verify secret matches Portal |
| Duplicate events | Flexport retries on timeout | Implement idempotency with event ID dedup |
| Missing events | Endpoint unreachable | Monitor uptime, use dead letter queue |
| Slow processing | Complex handler logic | Acknowledge fast (200), process async |
Resources
Next Steps
For performance optimization, see flexport-performance-tuning.