Tracking Webhooks
Receive real-time notifications about order status changes via webhooks.
Webhook Events
Subscribe to the following events:
| Event | Description |
|---|---|
order.created | Order created |
order.picked_up | Package picked up |
order.in_transit | Package in transit |
order.out_for_delivery | Out for delivery |
order.delivered | Package delivered |
order.failed_delivery | Delivery failed |
order.cancelled | Order cancelled |
order.exception | Delivery exception |
Webhook Payload
When an event occurs, Fuuffy sends a POST request to your webhook URL:
{
"event": "order.in_transit",
"timestamp": "2024-01-16T08:15:00Z",
"data": {
"order_id": "order_1a2b3c4d5e6f",
"tracking_number": "FUF123456789",
"status": "in_transit",
"location": {
"city": "Chicago",
"state": "IL",
"country": "US"
},
"description": "Package in transit to destination",
"estimated_delivery": "2024-01-18T17:00:00Z"
}
}
Setting Up Webhooks
1. Create a Webhook Endpoint
Create an endpoint in your application to receive webhook notifications:
<?php
// webhook.php
// Get the raw POST data
$payload = file_get_contents('php://input');
$event = json_decode($payload, true);
// Verify webhook signature (recommended)
$signature = $_SERVER['HTTP_X_FUUFFY_SIGNATURE'] ?? '';
if (!verifySignature($payload, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
// Process the event
switch ($event['event']) {
case 'order.delivered':
handleDelivered($event['data']);
break;
case 'order.in_transit':
handleInTransit($event['data']);
break;
// Handle other events...
}
// Return 200 OK
http_response_code(200);
echo json_encode(['received' => true]);
function verifySignature($payload, $signature) {
$secret = getenv('FUUFFY_WEBHOOK_SECRET');
$expected = hash_hmac('sha256', $payload, $secret);
return hash_equals($expected, $signature);
}
function handleDelivered($data) {
// Update your database, send notifications, etc.
error_log("Order {$data['tracking_number']} delivered");
}
function handleInTransit($data) {
// Update tracking status in your system
error_log("Order {$data['tracking_number']} in transit");
}
?>
2. Register Your Webhook URL
Contact support to register your webhook URL, or use the API (if available):
curl -X POST ${API_URL}/v1/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourdomain.com/webhook.php",
"events": [
"order.delivered",
"order.in_transit",
"order.exception"
]
}'
Webhook Security
Signature Verification
All webhook requests include an X-Fuuffy-Signature header containing an HMAC SHA256 signature:
<?php
function verifyWebhookSignature($payload, $signature, $secret) {
$expected_signature = hash_hmac('sha256', $payload, $secret);
return hash_equals($expected_signature, $signature);
}
// Usage
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_FUUFFY_SIGNATURE'] ?? '';
$secret = getenv('FUUFFY_WEBHOOK_SECRET');
if (!verifyWebhookSignature($payload, $signature, $secret)) {
http_response_code(401);
exit('Invalid signature');
}
?>
Best Practices
- Verify signatures - Always verify the webhook signature
- Use HTTPS - Webhook URLs must use HTTPS
- Return 200 quickly - Process events asynchronously
- Handle duplicates - Events may be sent multiple times
- Implement retry logic - Handle temporary failures gracefully
Webhook Retry Policy
If your endpoint returns a non-2xx status code or times out:
- Retry 1: After 1 minute
- Retry 2: After 5 minutes
- Retry 3: After 15 minutes
- Retry 4: After 1 hour
- Retry 5: After 6 hours
After 5 failed attempts, the webhook is disabled and you'll receive an email notification.
Testing Webhooks
Use tools like webhook.site or ngrok to test webhooks locally:
# Start ngrok
ngrok http 8000
# Use the ngrok URL as your webhook endpoint
https://abc123.ngrok.io/webhook.php