Skip to main content

Tracking Webhooks

Receive real-time notifications about order status changes via webhooks.

Webhook Events

Subscribe to the following events:

EventDescription
order.createdOrder created
order.picked_upPackage picked up
order.in_transitPackage in transit
order.out_for_deliveryOut for delivery
order.deliveredPackage delivered
order.failed_deliveryDelivery failed
order.cancelledOrder cancelled
order.exceptionDelivery 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

  1. Verify signatures - Always verify the webhook signature
  2. Use HTTPS - Webhook URLs must use HTTPS
  3. Return 200 quickly - Process events asynchronously
  4. Handle duplicates - Events may be sent multiple times
  5. 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

Next Steps