Receive real-time order status updates via outgoing webhooks. Perfect for WhatsApp automation, CRM sync, and order tracking.
Events are triggered automatically when order data changes. Each event sends a POST request to your configured endpoint.
| Event Name | Description | Trigger |
|---|---|---|
order.status_updated |
Fires when an order's shipping status changes | Active |
Possible old_status → new_status combinations you'll receive in webhooks.
| From (old_status) | To (new_status) | Meaning | |
|---|---|---|---|
| pending | → | picked_up | Order picked up from warehouse |
| picked_up | → | preparing | Fulfiller is preparing the order |
| preparing | → | prepared | Order packed and ready to ship |
| prepared | → | out_for_delivery | Shipped, on the way to customer |
| out_for_delivery | → | delivered | Successfully delivered |
| out_for_delivery | → | returned | Customer refused / delivery failed |
| returned | → | delivered | Re-attempted and delivered |
| returned | → | return_received | Return received at warehouse |
| return_received | → | returned_to_stock | Product returned to inventory |
Every webhook request includes these headers for verification and context.
order.status_updated)application/jsonExample payload for order.status_updated event.
{ "event": "order.status_updated", "timestamp": "2026-05-09T12:00:00+02:00", "order": { "reference": "ORD-000129", "old_status": "out_for_delivery", "new_status": "delivered", "amount": 1799, "currency": "MAD", "tracking_number": "F-CSA6SFJ6EMY", "delivery_notes": "Call before delivery", "created_at": "2026-05-08T12:25:44+01:00" }, "customer": { "name": "Karim Mansouri", "phone": "+212661234567", "city": "Casablanca", "address": "123 Bd Mohammed V" }, "product": { "name": "Argivit Classic Tablets", "sku": "MA-ArgivitClassic" }, "items": [ { "product_name": "Argivit Classic Tablets", "sku": "MA-ArgivitClassic", "quantity": 1, "price": 1799 } ] }
Verify the X-Webhook-Signature header to ensure the request is authentic and hasn't been tampered with.
const crypto = require('crypto'); function verifyWebhook(body, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(body) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) ); } // Usage in Express app.post('/webhook', (req, res) => { const signature = req.headers['x-webhook-signature']; const isValid = verifyWebhook( JSON.stringify(req.body), signature, 'your_secret_key' ); if (!isValid) return res.status(401).send('Invalid signature'); // Process the webhook... });
import hmac, hashlib def verify_webhook(body, signature, secret): expected = hmac.new( secret.encode('utf-8'), body.encode('utf-8'), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature) # Usage in Flask @app.route('/webhook', methods=['POST']) def handle_webhook(): signature = request.headers.get('X-Webhook-Signature') if not verify_webhook( request.get_data(as_text=True), signature, 'your_secret_key' ): return 'Invalid', 401 # Process the webhook...
function verifyWebhook($body, $signature, $secret) { $expected = hash_hmac('sha256', $body, $secret); return hash_equals($expected, $signature); } // Usage $body = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE']; $secret = 'your_secret_key'; if (!verifyWebhook($body, $signature, $secret)) { http_response_code(401); die('Invalid signature'); } $data = json_decode($body, true); // Process the webhook...
order.reference + new_status as a unique key to avoid duplicates