| name | replicate-webhooks |
| description | Receive and verify Replicate webhooks. Use when setting up Replicate webhook handlers, debugging signature verification, or handling prediction events like start, output, logs, or completed.
|
| license | MIT |
| metadata | {"author":"hookdeck","version":"0.1.0","repository":"https://github.com/hookdeck/webhook-skills"} |
Replicate Webhooks
When to Use This Skill
- Setting up Replicate webhook handlers
- Debugging signature verification failures
- Understanding Replicate event types and payloads
- Handling prediction lifecycle events (start, output, logs, completed)
Essential Code (USE THIS)
Express Webhook Handler
const express = require('express');
const crypto = require('crypto');
const app = express();
app.post('/webhooks/replicate',
express.raw({ type: 'application/json' }),
async (req, res) => {
const webhookId = req.headers['webhook-id'];
const webhookTimestamp = req.headers['webhook-timestamp'];
const webhookSignature = req.headers['webhook-signature'];
if (!webhookId || !webhookTimestamp || !webhookSignature) {
return res.status(400).json({ error: 'Missing required webhook headers' });
}
const secret = process.env.REPLICATE_WEBHOOK_SECRET;
const signedContent = `${webhookId}.${webhookTimestamp}.${req.body}`;
try {
const secretBytes = Buffer.from(secret.split('_')[1], 'base64');
const expectedSignature = crypto
.createHmac('sha256', secretBytes)
.update(signedContent)
.digest('base64');
const signatures = webhookSignature.split(' ').map(sig => {
const parts = sig.split(',');
return parts.length > 1 ? parts[1] : sig;
});
const isValid = signatures.some(sig => {
try {
return crypto.timingSafeEqual(
Buffer.from(sig),
Buffer.from(expectedSignature)
);
} catch {
return false;
}
});
if (!isValid) {
return res.status(400).json({ error: 'Invalid signature' });
}
const timestamp = parseInt(webhookTimestamp, 10);
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime - timestamp > 300) {
return res.status(400).json({ error: 'Timestamp too old' });
}
} catch (err) {
console.error('Signature verification error:', err);
return res.status(400).json({ error: 'Invalid signature' });
}
const prediction = JSON.parse(req.body.toString());
console.log('Prediction webhook received:', {
id: prediction.id,
status: prediction.status,
version: prediction.version
});
switch (prediction.status) {
case 'starting':
console.log('Prediction starting:', prediction.id);
break;
case 'processing':
console.log('Prediction processing:', prediction.id);
if (prediction.logs) {
console.log('Logs:', prediction.logs);
}
break;
case 'succeeded':
console.log('Prediction completed successfully:', prediction.id);
console.log('Output:', prediction.output);
break;
case 'failed':
console.log('Prediction failed:', prediction.id);
console.log('Error:', prediction.error);
break;
case 'canceled':
console.log('Prediction canceled:', prediction.id);
break;
default:
console.log('Unknown status:', prediction.status);
}
res.status(200).json({ received: true });
}
);
Common Prediction Statuses
| Status | Description | Common Use Cases |
|---|
starting | Prediction is initializing | Show loading state in UI |
processing | Model is running | Display progress, show logs if available |
succeeded | Prediction completed successfully | Process final output, update UI |
failed | Prediction encountered an error | Show error message to user |
canceled | Prediction was canceled | Clean up resources, notify user |
Environment Variables
REPLICATE_WEBHOOK_SECRET=whsec_your_secret_here
Local Development
For local webhook testing, install the Hookdeck CLI:
Then start the tunnel:
npx hookdeck-cli listen 3000 replicate --path /webhooks/replicate
No account required. Provides local tunnel + web UI for inspecting requests.
Reference Materials
Resources for Implementation
Framework Examples
Documentation
Recommended: webhook-handler-patterns
Enhance your webhook implementation with these patterns:
Related Skills