Webhook Events
Complete documentation for all webhook event types and their payloads.
Event Format
All events follow this structure:
{
"id": "evt_abc123xyz",
"event": "event.type",
"created_at": "2024-01-15T14:30:00Z",
"data": {
// Event-specific data
}
}
Tag Events
tag.created
Fired when a new tag is created.
{
"id": "evt_abc123",
"event": "tag.created",
"created_at": "2024-01-15T14:30:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k",
"title": "New Product Tag",
"owner_id": "user_456",
"permissions": {
"read": "public",
"write": "owner"
},
"created_at": "2024-01-15T14:30:00Z"
}
}
}
tag.updated
Fired when a tag's content or settings are modified.
{
"id": "evt_def456",
"event": "tag.updated",
"created_at": "2024-01-15T15:00:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k",
"title": "Updated Product Tag",
"updated_at": "2024-01-15T15:00:00Z"
},
"changes": {
"title": {
"from": "New Product Tag",
"to": "Updated Product Tag"
},
"content": true
}
}
}
tag.deleted
Fired when a tag is deleted.
{
"id": "evt_ghi789",
"event": "tag.deleted",
"created_at": "2024-01-15T16:00:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k",
"title": "Deleted Tag"
},
"deleted_by": "user_456"
}
}
tag.viewed
Fired when someone views a tag.
{
"id": "evt_jkl012",
"event": "tag.viewed",
"created_at": "2024-01-15T14:35:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k",
"title": "Product Tag"
},
"view": {
"source": "qr_scan",
"device": "mobile",
"browser": "Safari",
"os": "iOS",
"country": "US",
"region": "California"
}
}
}
QR Code Events
qr.scanned
Fired when a QR code is scanned (distinct from tag.viewed for scan-specific tracking).
{
"id": "evt_mno345",
"event": "qr.scanned",
"created_at": "2024-01-15T14:35:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k"
},
"scan": {
"device": "mobile",
"os": "iOS",
"country": "US",
"city": "San Francisco",
"coordinates": {
"lat": 37.7749,
"lng": -122.4194
}
}
}
}
qr.generated
Fired when a QR code is generated or downloaded.
{
"id": "evt_pqr678",
"event": "qr.generated",
"created_at": "2024-01-15T14:40:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k"
},
"qr": {
"format": "png",
"size": 512,
"generated_by": "user_456"
}
}
}
File Events
file.uploaded
Fired when a file is uploaded to a tag.
{
"id": "evt_stu901",
"event": "file.uploaded",
"created_at": "2024-01-15T14:45:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k"
},
"file": {
"id": "file_xyz",
"name": "product-manual.pdf",
"mime_type": "application/pdf",
"size": 2457600,
"uploaded_by": "user_456"
}
}
}
file.deleted
Fired when a file is removed from a tag.
{
"id": "evt_vwx234",
"event": "file.deleted",
"created_at": "2024-01-15T14:50:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k"
},
"file": {
"id": "file_xyz",
"name": "product-manual.pdf"
},
"deleted_by": "user_456"
}
}
file.downloaded
Fired when a file is downloaded.
{
"id": "evt_yz567",
"event": "file.downloaded",
"created_at": "2024-01-15T14:55:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k"
},
"file": {
"id": "file_xyz",
"name": "product-manual.pdf"
},
"download": {
"device": "desktop",
"country": "US"
}
}
}
Sharing Events
tag.shared
Fired when a tag is shared with someone.
{
"id": "evt_share123",
"event": "tag.shared",
"created_at": "2024-01-15T15:00:00Z",
"data": {
"tag": {
"id": "tag_123",
"short_id": "a7Bx9k",
"title": "Shared Tag"
},
"share": {
"shared_with": "user@example.com",
"permission": "view",
"shared_by": "user_456"
}
}
}
Event Filtering
Subscribe to Specific Events
Only receive events you need:
{
"events": ["tag.created", "qr.scanned"]
}
Filter by Tag
Limit events to specific tags (coming soon):
{
"events": ["*"],
"filter": {
"tag_ids": ["tag_123", "tag_456"]
}
}
Handling Events
Event Type Switch
app.post('/webhook', (req, res) => {
const { event, data } = req.body;
switch (event) {
case 'tag.created':
handleTagCreated(data.tag);
break;
case 'tag.updated':
handleTagUpdated(data.tag, data.changes);
break;
case 'tag.deleted':
handleTagDeleted(data.tag);
break;
case 'tag.viewed':
trackView(data.tag, data.view);
break;
case 'qr.scanned':
trackScan(data.tag, data.scan);
break;
case 'file.uploaded':
handleFileUpload(data.tag, data.file);
break;
default:
console.log(`Unhandled event: ${event}`);
}
res.sendStatus(200);
});
Using Event ID
Deduplicate with event ID:
const processedEvents = new Set();
app.post('/webhook', (req, res) => {
const { id, event, data } = req.body;
// Check for duplicate
if (processedEvents.has(id)) {
return res.sendStatus(200);
}
processedEvents.add(id);
handleEvent(event, data);
res.sendStatus(200);
});
Best Practices
Handle All Subscribed Events
- Don't ignore events you subscribed to
- Log unknown events for debugging
- Update handling when you add events
Be Idempotent
- Same event processed multiple times = same result
- Use event ID for deduplication
- Design for at-least-once delivery
Respond Quickly
- Process asynchronously if needed
- Respond with 200 immediately
- Queue heavy processing