Webhooks
Receive real-time HTTP POST notifications when events occur on your TAGVU tags, batches, and orders.
Setup
1. Register a webhook URL
Navigate to your company dashboard at app.tag.vu/dashboard/settings/webhooks and add your HTTPS endpoint URL.
2. Select events
Choose which events to subscribe to. You can subscribe to all events or select specific ones.
3. Receive and verify
Each webhook includes a signature in the X-Tagvu-Signature header for verification.
Signature Verification
Every webhook request includes an HMAC-SHA256 signature. Verify it to ensure the request came from TAGVU.
import crypto from 'crypto';
function verifyWebhook(payload: string, signature: string, secret: string): boolean {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post('/webhooks/tagvu', (req, res) => {
const signature = req.headers['x-tagvu-signature'] as string;
const isValid = verifyWebhook(
JSON.stringify(req.body),
signature,
process.env.TAGVU_WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the event
const { event, data } = req.body;
console.log(`Received: ${event}`, data);
res.status(200).json({ received: true });
});Retry Policy
- Webhooks expect a 2xx response within 30 seconds.
- Failed deliveries are retried with exponential backoff: 1min, 5min, 30min, 2h, 24h.
- After 5 consecutive failures, the webhook is marked as disabled.
- You can re-enable disabled webhooks from your dashboard.
- Delivery logs are available for the last 7 days.
Event Types
tag.scanned
Fired when a tag is scanned by anyone. Includes location, device context, and tag status.
View payload example
{
"event": "tag.scanned",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"tag_id": "550e8400-e29b-41d4-a716-446655440000",
"tag_code": "A1B2-C3D4-EF",
"status": "active",
"scan": {
"id": "uuid",
"location_text": "Brussels Central Station",
"location_lat": 50.8453,
"location_lng": 4.3570,
"device_type": "mobile",
"browser": "Chrome",
"os": "Android"
}
}
}tag.lost_mode_toggled
Fired when lost mode is enabled or disabled on a tag.
View payload example
{
"event": "tag.lost_mode_toggled",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"tag_id": "550e8400-e29b-41d4-a716-446655440000",
"tag_code": "A1B2-C3D4-EF",
"lost_mode_enabled": true,
"reason": "Lost at the park"
}
}tag.claimed
Fired when a tag is claimed by a user using the claim PIN.
View payload example
{
"event": "tag.claimed",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"tag_id": "550e8400-e29b-41d4-a716-446655440000",
"tag_code": "A1B2-C3D4-EF",
"claimed_by": "user-uuid"
}
}tag.transferred
Fired when tag ownership is transferred to another user.
View payload example
{
"event": "tag.transferred",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"tag_id": "550e8400-e29b-41d4-a716-446655440000",
"from_user": "user-uuid-1",
"to_user": "user-uuid-2"
}
}tag.status_changed
Fired when a tag transitions between statuses (e.g., active to expired).
View payload example
{
"event": "tag.status_changed",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"tag_id": "550e8400-e29b-41d4-a716-446655440000",
"previous_status": "active",
"new_status": "expired",
"reason": "Service period ended"
}
}batch.status_changed
Fired when a batch transitions through the production pipeline.
View payload example
{
"event": "batch.status_changed",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"batch_id": "uuid",
"previous_status": "in_production",
"new_status": "qc_pending",
"quantity": 500
}
}order.status_changed
Fired when an order status changes (confirmed, shipped, delivered, etc.).
View payload example
{
"event": "order.status_changed",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"order_id": "uuid",
"previous_status": "processing",
"new_status": "shipped",
"tracking_number": "1Z999AA1234567890"
}
}member.invited
Fired when a new member is invited to a company.
View payload example
{
"event": "member.invited",
"timestamp": "2026-03-27T10:30:00Z",
"data": {
"company_id": "uuid",
"email": "new.member@example.com",
"role": "operator",
"invited_by": "user-uuid"
}
}