Webhooks
Configure a webhook URL on your API key to receive a signed HTTP POST when tasks complete or fail.
Pass webhookUrl when creating an API key:
curl -X POST https://api.playcut.ai/api/v1/api-keys \ -H "Authorization: Bearer $CLERK_SESSION_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "label": "Production", "webhookUrl": "https://your-app.com/webhooks/playcut" }'The response includes a one-time webhookSecret. Store it securely.
{ "key": "pk_live_...", "webhookSecret": "a3f8c2d1...", "apiKey": { ... }}Payload shape
Section titled “Payload shape”{ "id": "whev_64f3a1b2c3d4e5f6", "type": "task.completed", "createdAt": "2026-05-18T12:00:00.000Z", "data": { "taskId": "abc123", "taskType": "GEMINI_TEXT_TO_IMAGE", "status": "COMPLETED", "output": { "assetIds": ["asset_xyz"] } }}For failed tasks the type is task.failed and data includes an error object.
Verifying signatures
Section titled “Verifying signatures”Every request includes X-Playcut-Signature: sha256=<hex>. Verify it before processing:
import { createHmac } from "crypto"import express from "express"
app.post("/webhooks/playcut", express.raw({ type: "application/json" }), (req, res) => { const sig = req.headers["x-playcut-signature"] as string const expected = "sha256=" + createHmac("sha256", process.env.PLAYCUT_WEBHOOK_SECRET!) .update(req.body) .digest("hex")
if (expected !== sig) return res.status(401).send("Invalid signature")
const event = JSON.parse(req.body.toString()) // handle event... res.json({ ok: true })})import hmac, hashlibfrom flask import Flask, request
app = Flask(__name__)
@app.route("/webhooks/playcut", methods=["POST"])def webhook(): sig = request.headers.get("X-Playcut-Signature", "") secret = os.environ["PLAYCUT_WEBHOOK_SECRET"].encode() expected = "sha256=" + hmac.new(secret, request.data, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, sig): return "Invalid signature", 401 event = request.get_json(force=True) # handle event... return {"ok": True}Retry schedule
Section titled “Retry schedule”| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 60 seconds |
| 3 | 5 minutes |
After 3 failed attempts the delivery is permanently marked as failed.
Testing
Section titled “Testing”Send a synthetic event to verify your endpoint:
curl -X POST https://api.playcut.ai/api/v1/api-keys/{keyId}/webhook/test \ -H "Authorization: Bearer $CLERK_SESSION_TOKEN"{ "delivered": true, "httpStatus": 200 }