Agent skill
Breakcold Webhooks Skill
Receive and verify Breakcold webhooks (the sales CRM at breakcold.com). Use when setting up a Breakcold outbound webhook handler, debugging X-Webhook-Signature verification, or handling record.created, record.updated, note.created, task.completed, relation.added, call.linked or file.uploaded events.
Install this skill
npx skills add hookdeck/webhook-skills --skill breakcold-webhooks
Breakcold (breakcold.com) is a sales CRM. Its outbound webhooks send an HTTPS POST with a JSON body whenever records, notes, tasks, relations, calls or files change in a workspace.
When to Use This Skill
- How do I receive Breakcold webhooks?
- How do I verify the Breakcold
X-Webhook-Signatureheader? - Why does my Breakcold webhook signature verification fail?
- How do I handle
record.created,note.createdortask.completedevents?
Resources
references/overview.md- events, headers, payload envelope, delivery behaviourreferences/setup.md- create the outbound webhook and copy the signing secretreferences/verification.md- signature details, gotchas, debuggingexamples/- runnable Express, Next.js and FastAPI handlers with tests
Verification (core)
Breakcold signs {X-Webhook-Timestamp}.{raw body} with HMAC-SHA256 (lowercase hex) keyed with the endpoint's signing secret, and sends it as X-Webhook-Signature: sha256=<hex>.
const crypto = require('crypto');
function verifyBreakcoldSignature(rawBody, signatureHeader, timestampHeader, secret) {
if (!signatureHeader || !timestampHeader || !secret) return false;
const digest = signatureHeader.replace(/^sha256=/i, ''); // prefix optional
if (!/^[0-9a-f]{64}$/i.test(digest)) return false; // validate before decoding
const signed = Buffer.concat([
Buffer.from(timestampHeader, 'latin1'), Buffer.from('.'), rawBody, // rawBody is a Buffer
]);
const expected = crypto.createHmac('sha256', secret).update(signed).digest();
return crypto.timingSafeEqual(Buffer.from(digest, 'hex'), expected);
}
- Use the raw body bytes (
express.raw({ type: '*/*' }),await request.arrayBuffer(),await request.body()). NeverJSON.parseand re-serialize before verifying. - The secret is a string used as UTF-8 bytes as-is (no hex or base64 decoding).
- Reject with 401 when the signature or timestamp header is missing, malformed or does not match.
- No timestamp window by default. Hookdeck retries and replays resend the original
X-Webhook-Timestamp, so a fixed window rejects legitimate retries. The examples offer an opt-inBREAKCOLD_(Unix seconds; unset orWEBHOOK_ TOLERANCE_ SECONDS 0= off).
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
Dispatch on the body's event field (also sent as X-Webhook-Event).
| Event | Fires when |
|---|---|
record.created / record.updated / record.deleted | A record is created, a field changes, or it is deleted |
note.created / note.updated / note.deleted | A note is added to, edited on, or removed from a record |
task.created / task.completed | A task is linked to a record, or marked complete |
relation.added / relation.removed | A relation between records is added or removed |
call.linked / call.unlinked | A call recording is linked to or unlinked from a record |
file.uploaded / file.deleted | A file is added to or removed from a record |
webhook.test | You press the endpoint's test button |
Use X-Webhook-Delivery-Id for idempotency. Any 2xx accepts a delivery; Breakcold makes up to 3 attempts (retries after about 5 s and 30 s), times out after 10 s, and disables an endpoint after 50 consecutive failures.
Environment Variables
BREAKCOLD_WEBHOOK_SECRET=your_breakcold_signing_secret
# Optional. Unset or 0 = no timestamp check.
BREAKCOLD_WEBHOOK_TOLERANCE_SECONDS=300
Local Development
npx hookdeck-cli listen 3000 breakcold --path /webhooks/breakcold
No account required. Use 8000 instead of 3000 for FastAPI.