Webhooks
Last updated July 30, 2026
Webhooks let your backend receive shipment status changes the moment they happen, instead of polling. Configure endpoints from the merchant dashboard under Webhooks, no API call needed to set one up.
Events
| Event | Fires when |
|---|---|
shipment.created | A shipment is successfully created and charged |
shipment.assigned | A delivery agent is assigned |
shipment.picked_up | The agent has picked up the package |
shipment.in_transit | The agent is en route to the recipient |
shipment.delivered | The package has been delivered |
shipment.failed | The shipment could not be completed (automatically refunded) |
shipment.cancelled | You or 7feastr cancelled the shipment (automatically refunded) |
shipment.refunded | A refund was issued |
You can subscribe a single endpoint to specific events, or to * for everything.
Payload
Every delivery is a POST request with this JSON body:
{
"event": "shipment.delivered",
"data": {
"shipmentId": "6890...",
"trackingCode": "7F-20260730-4F91A2C8",
"status": "delivered"
},
"sentAt": "2026-07-30T22:11:03.412Z"
}
Verifying the signature
Every request includes an X-7feastr-Signature header: an HMAC-SHA256 hex digest of the exact raw request body, signed with your webhook's signing secret (shown once at creation, and always viewable again from the dashboard since it's needed to configure your endpoint).
Always verify this signature before trusting a webhook payload. Anyone can send a POST request to your endpoint; only a correctly signed one actually came from 7feastr.
Node.js / Express example:
import crypto from 'crypto';
function verify7feastrSignature(rawBody, signatureHeader, webhookSecret) {
const expected = crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader),
);
}
app.post('/webhooks/7feastr', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-7feastr-signature'];
const isValid = verify7feastrSignature(req.body.toString('utf8'), signature, process.env.SEVENFEASTR_WEBHOOK_SECRET);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
const { event, data } = JSON.parse(req.body.toString('utf8'));
// handle event
res.status(200).send('ok');
});
Note the raw, unparsed body is what gets signed, if your framework parses JSON before you can access the raw bytes, use its raw-body middleware for this specific route (as shown above with express.raw).
Retries and auto-disable
If your endpoint doesn't respond with a 2xx status within 8 seconds, the delivery is marked failed. After 10 consecutive failures, the webhook is automatically disabled (you can re-enable it from the dashboard once your endpoint is fixed) so a broken endpoint on your side never causes runaway retries. Each webhook's last delivery status is always visible on the dashboard, and you can send a manual test event at any time to verify your endpoint is working correctly before relying on it.
Requirements
Production webhook URLs must use HTTPS. Sandbox accepts either HTTP or HTTPS for local testing.