Webhooks
Before you start
Section titled “Before you start”Plunk sets up your webhook URL (https only) and gives you a signing secret that starts with whsec_. Ask through support to turn it on or rotate the secret.
Events
Section titled “Events”| Event | When |
|---|---|
comcol.request.submitted |
A shopper submits a request |
comcol.request.accepted |
Your team accepts it |
comcol.request.declined |
Your team declines it |
The delivery
Section titled “The delivery”POST https://your.example.com/plunk/webhooksContent-Type: application/jsonx-plunk-event: comcol.request.submittedx-plunk-signature: 5c1f…
{ "event": "comcol.request.submitted", "occurredAt": "2026-10-13T15:02:11.4820000Z", "tenantId": "a123456789012", "request": { "id": 1182, "status": "submitted_for_review", "frameSku": "SF-1042", "quantity": 1, "renderUrl": "https://…", "customer": { "name": "…", "email": "…", "phone": "…" } }}Check the signature
Section titled “Check the signature”Compute the HMAC over the exact bytes you received (not a re-serialized copy) and compare in constant time.
const crypto = require('crypto');
const expected = crypto.createHmac('sha256', process.env.PLUNK_WEBHOOK_SECRET) .update(rawBody).digest('hex');const got = Buffer.from(req.headers['x-plunk-signature'] || '');const ok = got.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), got);import hashlib, hmac, os
expected = hmac.new( os.environ["PLUNK_WEBHOOK_SECRET"].encode(), raw_body, hashlib.sha256).hexdigest()ok = hmac.compare_digest(expected, request.headers.get("x-plunk-signature", ""))Delivery rules
Section titled “Delivery rules”- Delivery is a single attempt with a 4-second timeout, with no retries yet.
- Answer with any 2xx quickly and do the work afterwards.
- Use
GET /cx/v1/comcol/requeststo catch up on anything you missed.
Related
Section titled “Related”Was this helpful?
Still stuck? Contact support and include the job or page you were on.