Skip to content

Webhooks

Webhooks let you receive HTTP callbacks when file statuses change. Instead of polling, your server gets notified in real time.

EventTrigger
file.hotFile confirmed and stored in hot cache
file.syncedFile successfully synced to Walrus
file.coldFile evicted from hot cache (Walrus only)
file.errorFile processing failed
const webhook = await tusky.webhooks.create({
url: 'https://example.com/tusky-webhook',
events: ['file.synced', 'file.error'],
});
// Save the secret — it's only shown once
console.log(webhook.secret);

Tusky sends a POST request with a JSON body:

{
"event": "file.synced",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"fileId": "file-uuid",
"fileName": "report.pdf",
"vaultId": "vault-uuid",
"status": "synced",
"sizeBytes": 204800,
"walrusBlobId": "blob-id-hash"
}
}

For file.error events, the payload includes an error field:

{
"event": "file.error",
"timestamp": "2025-01-15T10:30:00.000Z",
"data": {
"fileId": "file-uuid",
"fileName": "report.pdf",
"vaultId": "vault-uuid",
"status": "error",
"sizeBytes": 204800,
"error": "Walrus sync failed: insufficient WAL balance"
}
}

Every webhook request includes an X-Tusky-Signature header. Verify it using HMAC-SHA-256 with your webhook secret:

import { createHmac } from 'crypto';
function verifyWebhook(body: string, signature: string, secret: string): boolean {
const expected = createHmac('sha256', secret).update(body).digest('hex');
return signature === expected;
}
// In your webhook handler
app.post('/tusky-webhook', (req, res) => {
const signature = req.headers['x-tusky-signature'] as string;
if (!verifyWebhook(JSON.stringify(req.body), signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = req.body;
console.log(`${event}: ${data.fileName}${data.status}`);
res.sendStatus(200);
});

Send a test delivery to verify your endpoint:

const delivery = await tusky.webhooks.test(webhook.id);
console.log(delivery.statusCode); // 200 if your server responded OK

Check the delivery history for a webhook:

const deliveries = await tusky.webhooks.listDeliveries(webhook.id, {
limit: 10,
});
for (const d of deliveries) {
console.log(`${d.event}${d.statusCode} (${d.success ? 'ok' : 'failed'})`);
}
// Update events or disable
await tusky.webhooks.update(webhook.id, {
events: ['file.synced'],
active: false,
});
// Delete
await tusky.webhooks.delete(webhook.id);