Webhooks

The Webhook of Shame.

Real-time event delivery to your endpoint, of your choosing. With signatures. And just a little extra.

Configure an endpoint

POST /v1/webhook_endpoints

{
  "url": "https://your-app.com/hooks/jakesux",
  "events": ["sigh.created", "yikes.critical"],
  "description": "production hook — approach with caution"
}

Event types

  • sigh.created — a sigh has been recorded
  • sigh.audible — a sigh was loud enough to be heard in an adjacent meeting
  • eyeroll.registered — an eyeroll has crossed p99
  • cringe.spiked — cringe levels exceeded 4σ of the daily mean
  • jake.said_actually — fires approximately every 11 minutes
  • jake.muted_himself — rare; archive for training data
  • yikes.critical — for when plain yikes aren't enough
  • recovery.false_alarm — you'd hoped; we dashed that hope
  • apology.retracted — Jake has taken back whatever he said earlier
  • vibes.off — vibes exceeded tolerance for current workspace

Payload shape

POST /your-endpoint
Content-Type: application/json
User-Agent: JakeSux-Webhook/1.0
X-JakeSux-Signature: sha256=3a7bd3e2360a3d29eea436fcfb7e44c735d117c42d1c1835420b6b9942dd4f1b
X-JakeSux-Shame-Level: 0.82
X-JakeSux-Delivery: wd_9f2e1d
X-JakeSux-Event: sigh.created

{
  "id": "evt_2x9k",
  "type": "sigh.created",
  "created": 1745432531,
  "data": {
    "intensity": "audible",
    "cause": "jake explained blockchain again",
    "duration_ms": 4800,
    "witnesses": 12
  },
  "shame": {
    "message": "you could have prevented this",
    "directed_at": "you, personally",
    "suggested_action": "consider your choices"
  }
}

Signature verification

Every request is signed with HMAC-SHA256 using your endpoint's signing secret. Verify before trusting the payload — especially the shame block.

import crypto from 'crypto';

function verifyJakeSuxSignature(rawBody, header, secret) {
  const [, sig] = header.split('=');
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(sig, 'hex'),
    Buffer.from(expected, 'hex')
  );
}

if (!verifyJakeSuxSignature(req.rawBody, req.headers['x-jakesux-signature'], secret)) {
  return res.status(401).send('invalid signature (and vibes)');
}

Retries

  • Webhooks retry up to 3 times with exponential backoff (30s, 5m, 30m)
  • Jake's apologies retry 0 times, with exponential blame
  • Failed deliveries appear in a dashboard called the Wall of Shame (Enterprise only)
  • Responses with 2xx status codes are considered successful. Anything else sighs audibly in our logs.

Best practices

  • Respond within 5 seconds. We time out past that, and then we remember.
  • Handle duplicate events idempotently — we may retry on transient failures
  • Do not log the shame block. It's for your eyes only.
  • Rotate your signing secret annually, or after every Jake-related incident (whichever comes first)
Need streaming instead? The Sigh SDK supports long-lived feed streams over SSE.