Skip to main content

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": "[email protected]",
"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

Next Steps