{"id":"8885b035-8fbc-4a74-8319-d6639e46c804","shortId":"3TMnK3","kind":"skill","title":"replicate-webhooks","tagline":"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.","description":"# Replicate Webhooks\n\n## When to Use This Skill\n\n- Setting up Replicate webhook handlers\n- Debugging signature verification failures\n- Understanding Replicate event types and payloads\n- Handling prediction lifecycle events (start, output, logs, completed)\n\n## Essential Code (USE THIS)\n\n### Express Webhook Handler\n\n```javascript\nconst express = require('express');\nconst crypto = require('crypto');\n\nconst app = express();\n\n// CRITICAL: Use express.raw() for webhook endpoint - Replicate needs raw body\napp.post('/webhooks/replicate',\n  express.raw({ type: 'application/json' }),\n  async (req, res) => {\n    // Get webhook headers\n    const webhookId = req.headers['webhook-id'];\n    const webhookTimestamp = req.headers['webhook-timestamp'];\n    const webhookSignature = req.headers['webhook-signature'];\n\n    // Verify we have required headers\n    if (!webhookId || !webhookTimestamp || !webhookSignature) {\n      return res.status(400).json({ error: 'Missing required webhook headers' });\n    }\n\n    // Manual signature verification (recommended approach)\n    const secret = process.env.REPLICATE_WEBHOOK_SECRET; // whsec_xxxxx from Replicate\n    const signedContent = `${webhookId}.${webhookTimestamp}.${req.body}`;\n\n    try {\n      // Extract base64 secret after 'whsec_' prefix\n      const secretBytes = Buffer.from(secret.split('_')[1], 'base64');\n      const expectedSignature = crypto\n        .createHmac('sha256', secretBytes)\n        .update(signedContent)\n        .digest('base64');\n\n      // Replicate can send multiple signatures, check each one\n      const signatures = webhookSignature.split(' ').map(sig => {\n        const parts = sig.split(',');\n        return parts.length > 1 ? parts[1] : sig;\n      });\n\n      const isValid = signatures.some(sig => {\n        try {\n          return crypto.timingSafeEqual(\n            Buffer.from(sig),\n            Buffer.from(expectedSignature)\n          );\n        } catch {\n          return false; // Different lengths = invalid\n        }\n      });\n\n      if (!isValid) {\n        return res.status(400).json({ error: 'Invalid signature' });\n      }\n\n      // Check timestamp to prevent replay attacks (5-minute window)\n      const timestamp = parseInt(webhookTimestamp, 10);\n      const currentTime = Math.floor(Date.now() / 1000);\n      if (currentTime - timestamp > 300) {\n        return res.status(400).json({ error: 'Timestamp too old' });\n      }\n    } catch (err) {\n      console.error('Signature verification error:', err);\n      return res.status(400).json({ error: 'Invalid signature' });\n    }\n\n    // Parse the verified webhook body\n    const prediction = JSON.parse(req.body.toString());\n\n    // Handle the prediction based on its status\n    console.log('Prediction webhook received:', {\n      id: prediction.id,\n      status: prediction.status,\n      version: prediction.version\n    });\n\n    switch (prediction.status) {\n      case 'starting':\n        console.log('Prediction starting:', prediction.id);\n        break;\n      case 'processing':\n        console.log('Prediction processing:', prediction.id);\n        if (prediction.logs) {\n          console.log('Logs:', prediction.logs);\n        }\n        break;\n      case 'succeeded':\n        console.log('Prediction completed successfully:', prediction.id);\n        console.log('Output:', prediction.output);\n        break;\n      case 'failed':\n        console.log('Prediction failed:', prediction.id);\n        console.log('Error:', prediction.error);\n        break;\n      case 'canceled':\n        console.log('Prediction canceled:', prediction.id);\n        break;\n      default:\n        console.log('Unknown status:', prediction.status);\n    }\n\n    res.status(200).json({ received: true });\n  }\n);\n```\n\n## Common Prediction Statuses\n\n| Status | Description | Common Use Cases |\n|--------|-------------|------------------|\n| `starting` | Prediction is initializing | Show loading state in UI |\n| `processing` | Model is running | Display progress, show logs if available |\n| `succeeded` | Prediction completed successfully | Process final output, update UI |\n| `failed` | Prediction encountered an error | Show error message to user |\n| `canceled` | Prediction was canceled | Clean up resources, notify user |\n\n## Environment Variables\n\n```bash\n# Your webhook signing secret from Replicate\nREPLICATE_WEBHOOK_SECRET=whsec_your_secret_here\n```\n\n## Local Development\n\nFor local webhook testing, install the Hookdeck CLI:\n\n```bash\n# Install via npm\nnpm install -g hookdeck-cli\n\n# Or via Homebrew\nbrew install hookdeck/hookdeck/hookdeck\n```\n\nThen start the tunnel:\n\n```bash\nhookdeck listen 3000 --path /webhooks/replicate\n```\n\nNo account required. Provides local tunnel + web UI for inspecting requests.\n\n## Reference Materials\n\n- [What are Replicate webhooks](references/overview.md) — Event types and payload structure\n- [Setting up webhooks](references/setup.md) — Dashboard configuration and signing secret\n- [Signature verification](references/verification.md) — Verification algorithm and common issues\n\n## Resources for Implementation\n\n### Framework Examples\n- [Express implementation](examples/express/) — Node.js with Express\n- [Next.js implementation](examples/nextjs/) — React framework with API routes\n- [FastAPI implementation](examples/fastapi/) — Python async framework\n\n### Documentation\n- [Official Replicate webhook docs](https://replicate.com/docs/topics/webhooks)\n- [Webhook setup guide](https://replicate.com/docs/topics/webhooks/setup-webhook)\n- [Webhook verification guide](https://replicate.com/docs/topics/webhooks/verify-webhook)\n\n## Recommended: webhook-handler-patterns\n\nEnhance your webhook implementation with these patterns:\n\n- [Handler sequence](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)\n- [Idempotency](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)\n- [Error handling](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)\n- [Retry logic](https://github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)\n\n## Related Skills\n\n- [stripe-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks) - Stripe payment webhooks\n- [github-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks) - GitHub repository events\n- [shopify-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks) - Shopify store events\n- [clerk-webhooks](https://github.com/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks) - Clerk authentication events\n- [webhook-handler-patterns](https://github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns) - Idempotency, error handling, retry logic\n- [hookdeck-event-gateway](https://github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway) - Webhook infrastructure that replaces your queue — guaranteed delivery, automatic retries, replay, rate limiting, and observability for your webhook handlers","tags":["replicate","webhooks","webhook","skills","hookdeck","agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks"],"capabilities":["skill","source-hookdeck","skill-replicate-webhooks","topic-agent-skills","topic-ai-coding","topic-api-integrations","topic-event-driven","topic-github-webhooks","topic-llm-tools","topic-shopify-webhooks","topic-stripe-webhooks","topic-webhook-security","topic-webhook-signatures","topic-webhooks"],"categories":["webhook-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/hookdeck/webhook-skills/replicate-webhooks","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add hookdeck/webhook-skills","source_repo":"https://github.com/hookdeck/webhook-skills","install_from":"skills.sh"}},"qualityScore":"0.484","qualityRationale":"deterministic score 0.48 from registry signals: · indexed on github topic:agent-skills · 69 github stars · SKILL.md body (7,143 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-02T06:55:47.347Z","embedding":null,"createdAt":"2026-04-18T22:13:59.194Z","updatedAt":"2026-05-02T06:55:47.347Z","lastSeenAt":"2026-05-02T06:55:47.347Z","tsv":"'/docs/topics/webhooks)':534 '/docs/topics/webhooks/setup-webhook)':540 '/docs/topics/webhooks/verify-webhook)':546 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':572 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':563 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':567 '/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':577 '/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks)':612 '/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':594 '/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':634 '/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':603 '/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':585 '/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':622 '/webhooks/replicate':89,461 '1':165,195,197 '10':238 '1000':243 '200':351 '300':247 '3000':459 '400':128,220,250,265 '5':231 'account':463 'algorithm':498 'api':519 'app':76 'app.post':88 'application/json':92 'approach':139 'async':93,525 'attack':230 'authent':614 'automat':643 'avail':381 'base':282 'base64':156,166,176 'bash':412,436,456 'bodi':87,274 'break':304,316,327,337,344 'brew':449 'buffer.from':163,206,208 'cancel':339,342,401,404 'case':298,305,317,328,338,362 'catch':210,256 'check':182,225 'clean':405 'clerk':608,613 'clerk-webhook':607 'cli':435,445 'code':60 'common':355,360,500 'complet':28,58,321,384 'configur':490 'console.error':258 'console.log':286,300,307,313,319,324,330,334,340,346 'const':67,71,75,99,105,111,140,149,161,167,185,190,199,234,239,275 'createhmac':170 'critic':78 'crypto':72,74,169 'crypto.timingsafeequal':205 'currenttim':240,245 'dashboard':489 'date.now':242 'debug':16,41 'default':345 'deliveri':642 'descript':359 'develop':427 'differ':213 'digest':175 'display':376 'doc':531 'document':527 'encount':393 'endpoint':83 'enhanc':552 'environ':410 'err':257,262 'error':130,222,252,261,267,335,395,397,568,624 'essenti':59 'event':22,47,54,480,597,606,615,630 'exampl':506 'examples/express':509 'examples/fastapi':523 'examples/nextjs':515 'expectedsignatur':168,209 'express':63,68,70,77,507,512 'express.raw':80,90 'extract':155 'fail':329,332,391 'failur':44 'fals':212 'fastapi':521 'final':387 'framework':505,517,526 'g':442 'gateway':631 'get':96 'github':590,595 'github-webhook':589 'github.com':562,566,571,576,584,593,602,611,621,633 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/error-handling.md)':570 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/handler-sequence.md)':561 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/idempotency.md)':565 'github.com/hookdeck/webhook-skills/blob/main/skills/webhook-handler-patterns/references/retry-logic.md)':575 'github.com/hookdeck/webhook-skills/tree/main/skills/clerk-webhooks)':610 'github.com/hookdeck/webhook-skills/tree/main/skills/github-webhooks)':592 'github.com/hookdeck/webhook-skills/tree/main/skills/hookdeck-event-gateway)':632 'github.com/hookdeck/webhook-skills/tree/main/skills/shopify-webhooks)':601 'github.com/hookdeck/webhook-skills/tree/main/skills/stripe-webhooks)':583 'github.com/hookdeck/webhook-skills/tree/main/skills/webhook-handler-patterns)':620 'guarante':641 'guid':537,543 'handl':20,51,279,569,625 'handler':15,40,65,550,559,618,653 'header':98,121,134 'homebrew':448 'hookdeck':434,444,457,629 'hookdeck-c':443 'hookdeck-event-gateway':628 'hookdeck/hookdeck/hookdeck':451 'id':104,290 'idempot':564,623 'implement':504,508,514,522,555 'infrastructur':636 'initi':366 'inspect':471 'instal':432,437,441,450 'invalid':215,223,268 'issu':501 'isvalid':200,217 'javascript':66 'json':129,221,251,266,352 'json.parse':277 'length':214 'lifecycl':53 'like':23 'limit':647 'listen':458 'load':368 'local':426,429,466 'log':26,57,314,379 'logic':574,627 'manual':135 'map':188 'materi':474 'math.floor':241 'messag':398 'minut':232 'miss':131 'model':373 'multipl':180 'need':85 'next.js':513 'node.js':510 'notifi':408 'npm':439,440 'observ':649 'offici':528 'old':255 'one':184 'output':25,56,325,388 'pars':270 'parseint':236 'part':191,196 'parts.length':194 'path':460 'pattern':551,558,619 'payload':50,483 'payment':587 'predict':21,52,276,281,287,301,308,320,331,341,356,364,383,392,402 'prediction.error':336 'prediction.id':291,303,310,323,333,343 'prediction.logs':312,315 'prediction.output':326 'prediction.status':293,297,349 'prediction.version':295 'prefix':160 'prevent':228 'process':306,309,372,386 'process.env.replicate':142 'progress':377 'provid':465 'python':524 'queue':640 'rate':646 'raw':86 'react':516 'receiv':4,289,353 'recommend':138,547 'refer':473 'references/overview.md':479 'references/setup.md':488 'references/verification.md':496 'relat':578 'replac':638 'replay':229,645 'replic':2,7,13,29,38,46,84,148,177,418,419,477,529 'replicate-webhook':1 'replicate.com':533,539,545 'replicate.com/docs/topics/webhooks)':532 'replicate.com/docs/topics/webhooks/setup-webhook)':538 'replicate.com/docs/topics/webhooks/verify-webhook)':544 'repositori':596 'req':94 'req.body':153 'req.body.tostring':278 'req.headers':101,107,113 'request':472 'requir':69,73,120,132,464 'res':95 'res.status':127,219,249,264,350 'resourc':407,502 'retri':573,626,644 'return':126,193,204,211,218,248,263 'rout':520 'run':375 'secret':141,144,157,416,421,424,493 'secret.split':164 'secretbyt':162,172 'send':179 'sequenc':560 'set':11,36,485 'setup':536 'sha256':171 'shopifi':599,604 'shopify-webhook':598 'show':367,378,396 'sig':189,198,202,207 'sig.split':192 'sign':415,492 'signatur':17,42,116,136,181,186,224,259,269,494 'signatures.some':201 'signedcont':150,174 'skill':35,579 'skill-replicate-webhooks' 'source-hookdeck' 'start':24,55,299,302,363,453 'state':369 'status':285,292,348,357,358 'store':605 'stripe':581,586 'stripe-webhook':580 'structur':484 'succeed':318,382 'success':322,385 'switch':296 'test':431 'timestamp':110,226,235,246,253 'topic-agent-skills' 'topic-ai-coding' 'topic-api-integrations' 'topic-event-driven' 'topic-github-webhooks' 'topic-llm-tools' 'topic-shopify-webhooks' 'topic-stripe-webhooks' 'topic-webhook-security' 'topic-webhook-signatures' 'topic-webhooks' 'tri':154,203 'true':354 'tunnel':455,467 'type':48,91,481 'ui':371,390,469 'understand':45 'unknown':347 'updat':173,389 'use':9,33,61,79,361 'user':400,409 'variabl':411 'verif':18,43,137,260,495,497,542 'verifi':6,117,272 'version':294 'via':438,447 'web':468 'webhook':3,8,14,30,39,64,82,97,103,109,115,133,143,273,288,414,420,430,478,487,530,535,541,549,554,582,588,591,600,609,617,635,652 'webhook-handler-pattern':548,616 'webhook-id':102 'webhook-signatur':114 'webhook-timestamp':108 'webhookid':100,123,151 'webhooksignatur':112,125 'webhooksignature.split':187 'webhooktimestamp':106,124,152,237 'whsec':145,159,422 'window':233 'xxxxx':146","prices":[{"id":"09df838f-21b4-49f3-92e3-4704e59f3443","listingId":"8885b035-8fbc-4a74-8319-d6639e46c804","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"hookdeck","category":"webhook-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T22:13:59.194Z"}],"sources":[{"listingId":"8885b035-8fbc-4a74-8319-d6639e46c804","source":"github","sourceId":"hookdeck/webhook-skills/replicate-webhooks","sourceUrl":"https://github.com/hookdeck/webhook-skills/tree/main/skills/replicate-webhooks","isPrimary":false,"firstSeenAt":"2026-04-18T22:13:59.194Z","lastSeenAt":"2026-05-02T06:55:47.347Z"}],"details":{"listingId":"8885b035-8fbc-4a74-8319-d6639e46c804","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"hookdeck","slug":"replicate-webhooks","github":{"repo":"hookdeck/webhook-skills","stars":69,"topics":["agent-skills","ai-coding","api-integrations","event-driven","github-webhooks","llm-tools","shopify-webhooks","stripe-webhooks","webhook-security","webhook-signatures","webhooks"],"license":"mit","html_url":"https://github.com/hookdeck/webhook-skills","pushed_at":"2026-02-25T14:00:40Z","description":"Webhook integration skills for AI coding agents (Claude Code, Cursor, Copilot). Step-by-step guidance for setting up webhook receivers, signature verification, and event handling for Stripe, Shopify, GitHub, and more. Built on the Agent Skills specification.","skill_md_sha":"4baeb1cfc64bf743b9d19ee0f51be2d04dd00b62","skill_md_path":"skills/replicate-webhooks/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/hookdeck/webhook-skills/tree/main/skills/replicate-webhooks"},"layout":"multi","source":"github","category":"webhook-skills","frontmatter":{"name":"replicate-webhooks","license":"MIT","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."},"skills_sh_url":"https://skills.sh/hookdeck/webhook-skills/replicate-webhooks"},"updatedAt":"2026-05-02T06:55:47.347Z"}}