skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
hookdeck/webhook-skills193 installs

replicate-webhooks

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.

How do I install this agent skill?

npx skills add https://github.com/hookdeck/webhook-skills --skill replicate-webhooks
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides safe, clean boilerplate examples for verifying and handling Replicate webhooks across multiple frameworks (Express, Next.js, and FastAPI). No security threats or malicious behaviors were detected.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

  • Runlayerwarn

    22/22 files flagged

What does this agent skill do?

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();

// CRITICAL: Use express.raw() for webhook endpoint - Replicate needs raw body
app.post('/webhooks/replicate',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    // Get webhook headers
    const webhookId = req.headers['webhook-id'];
    const webhookTimestamp = req.headers['webhook-timestamp'];
    const webhookSignature = req.headers['webhook-signature'];

    // Verify we have required headers
    if (!webhookId || !webhookTimestamp || !webhookSignature) {
      return res.status(400).json({ error: 'Missing required webhook headers' });
    }

    // Manual signature verification (recommended approach)
    const secret = process.env.REPLICATE_WEBHOOK_SECRET; // whsec_xxxxx from Replicate
    const signedContent = `${webhookId}.${webhookTimestamp}.${req.body}`;

    try {
      // Extract base64 secret after 'whsec_' prefix
      const secretBytes = Buffer.from(secret.split('_')[1], 'base64');
      const expectedSignature = crypto
        .createHmac('sha256', secretBytes)
        .update(signedContent)
        .digest('base64');

      // Replicate can send multiple signatures, check each one
      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; // Different lengths = invalid
        }
      });

      if (!isValid) {
        return res.status(400).json({ error: 'Invalid signature' });
      }

      // Check timestamp to prevent replay attacks (5-minute window)
      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' });
    }

    // Parse the verified webhook body
    const prediction = JSON.parse(req.body.toString());

    // Handle the prediction based on its status
    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

StatusDescriptionCommon Use Cases
startingPrediction is initializingShow loading state in UI
processingModel is runningDisplay progress, show logs if available
succeededPrediction completed successfullyProcess final output, update UI
failedPrediction encountered an errorShow error message to user
canceledPrediction was canceledClean up resources, notify user

Environment Variables

# Your webhook signing secret from Replicate
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

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/hookdeck/webhook-skills/replicate-webhooks">View replicate-webhooks on skillZs</a>