Webhooks Guide
Vectis sends real-time notifications to your application when events occur. Configure webhook endpoints to receive order updates, inventory changes, and fulfillment events.
Setting Up Webhooks
Create webhooks through the API for now (the dashboard form doesn’t send the required signing secret). Manage, test and view deliveries in Settings → Webhooks.
Your signing secret is the secret you send when you create the webhook (at least 16 characters). Vectis doesn’t display it later, so store it when you create the webhook.
Via API
curl -X POST https://acme.vectisoms.app/api/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.yoursite.com/webhooks/vectis",
"events": ["OrderCreated", "OrderShipped"],
"secret": "whsec_your_secret_here",
"isActive": true
}'
Event Types
Use * to receive every event.
Order Events
| Event | Description |
|---|---|
OrderCreated | New order received |
OrderConfirmed | Order confirmed for fulfillment |
OrderCancelled | Order was cancelled |
OrderShipped | All packages shipped |
OrderDelivered | Order delivered |
Package Events
| Event | Description |
|---|---|
PackageCreated | Package created for order |
PackageShipped | Package shipped with tracking |
PackageDelivered | Package delivered |
Inventory Events
| Event | Description |
|---|---|
InventoryAdjusted | Stock level changed |
Webhook Payload
Every webhook body has event, timestamp, and data. data varies by event and may include fields not shown here.
{
"event": "OrderShipped",
"timestamp": "2026-03-15T10:30:00Z",
"data": {
"orderId": "550e8400-e29b-41d4-a716-446655440000",
"trackingNumber": "1Z999AA10123456784",
"carrier": "UPS",
"shippedAt": "2026-03-15T10:29:58Z",
"eventId": "..."
}
}
Verifying Signatures
All outbound webhooks are signed with HMAC-SHA256. Always verify signatures before processing webhook data.
Headers
Each webhook request includes:
X-Vectis-Signature:t=<timestamp>,v1=<signature>(Unix seconds and hex HMAC-SHA256)X-Vectis-Event: the event nameX-Vectis-Delivery-Id: unique per delivery
Verification Process
- Take the timestamp
tfromX-Vectis-Signatureand concatenate:{t}.{raw_request_body} - Compute HMAC-SHA256 using your webhook secret
- Compare with the
v1value fromX-Vectis-Signature(timing-safe) - Reject if timestamp is older than 5 minutes
Node.js Example
const crypto = require('crypto');
function verifyWebhook(payload, header, secret) {
// Parse t (timestamp) and v1 (signature) from X-Vectis-Signature
const { t, v1 } = Object.fromEntries(header.split(',').map(p => p.split('=')));
// Check timestamp freshness (5 minute window)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(t)) > 300) {
return false;
}
// Compute expected signature
const signedPayload = `${t}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Timing-safe comparison (lengths must match first, or timingSafeEqual throws)
const received = Buffer.from(v1 || '');
const computed = Buffer.from(expected);
return received.length === computed.length && crypto.timingSafeEqual(received, computed);
}
// Express: keep the raw body for this route
app.post('/webhooks/vectis', express.raw({ type: 'application/json' }), (req, res) => {
const header = req.headers['x-vectis-signature'] || '';
const payload = req.body.toString('utf8'); // raw body, not parsed JSON
if (!verifyWebhook(payload, header, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(payload);
// Process event...
res.status(200).json({ received: true });
});
Python Example
import hmac
import hashlib
import time
def verify_webhook(payload: bytes, header: str, secret: str) -> bool:
# Parse t (timestamp) and v1 (signature) from X-Vectis-Signature
parts = dict(p.split("=", 1) for p in header.split(","))
timestamp, signature = parts["t"], parts["v1"]
# Check timestamp freshness
now = int(time.time())
if abs(now - int(timestamp)) > 300:
return False
# Compute expected signature
signed_payload = f"{timestamp}.{payload.decode()}"
expected = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Timing-safe comparison
return hmac.compare_digest(signature, expected)
Retry Behavior
Vectis makes up to three delivery attempts; after the third failure the delivery is marked failed and is not retried automatically. Your webhook stays active, and you can retry a failed delivery yourself (see Managing Webhooks).
A delivery is considered failed if:
- Your endpoint returns a non-2xx status code
- The request times out (30 seconds)
- Connection cannot be established
Best Practices
- Respond quickly — Return a 200 response immediately, then process asynchronously
- Handle duplicates: use
data.eventId(or theX-Vectis-Delivery-Idheader) to deduplicate. - Verify signatures — Never process unverified webhooks
- Use HTTPS — Webhook endpoints must use HTTPS
- Log everything — Store raw payloads for debugging
Testing Webhooks
Use the Test button in your dashboard to send a webhook.test event. Only webhooks subscribed to all events (*) receive it. You can also use tools like webhook.site during development.
Managing Webhooks
List Webhooks
curl https://acme.vectisoms.app/api/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Delete Webhook
curl -X DELETE https://acme.vectisoms.app/api/webhooks/{id} \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Delivery History and Retries
Open a webhook’s deliveries in Settings → Webhooks to see each delivery’s status, latest response code and response time, and number of attempts, and retry a failed delivery. Through the API: GET /api/webhooks/{id}/deliveries and POST /api/webhooks/{id}/deliveries/{deliveryId}/retry.