Agent skill
Belco Webhooks Skill
Receive and verify Belco webhooks. Use when setting up Belco (belco.io) webhook handlers, debugging x-hook-signature verification, or handling call and conversation events like conversation.created, conversation.closed and call.answered.
Install this skill
npx skills add hookdeck/webhook-skills --skill belco-webhooks
When to Use This Skill
- How do I receive Belco webhooks?
- How do I verify the
x-hook-signatureheader on a Belco webhook? - How do I handle
conversation.created,conversation.closedorcall.answeredevents? - Why is my Belco webhook signature verification failing?
- How do I deduplicate Belco webhook deliveries?
Verification (core)
Belco sends the header x-hook-signature: <hex> with no prefix. The value is the lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's secret string (its UTF-8 bytes, used as-is). Nothing else is signed: no timestamp, no id. It is not the Standard Webhooks spec. Validate the header's shape (exactly 64 hex characters), then compare in constant time. Verify over the raw bytes before parsing.
Node (compares validated ASCII hex, so Buffer.from(x, 'hex') is never called on untrusted input):
const crypto = require('crypto');
function verifyBelcoSignature(rawBody, signatureHeader, secret) {
if (typeof signatureHeader !== 'string' || !/^[0-9a-f]{64}$/i.test(signatureHeader)) return false;
const expected = Buffer.from(crypto.createHmac('sha256', secret).update(rawBody).digest('hex'));
const received = Buffer.from(signatureHeader.toLowerCase());
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}
Python (compare bytes so a non-ASCII header yields 401, not a 500):
import hashlib, hmac, re
def verify_belco_signature(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
if not signature_header or not re.fullmatch(r"[0-9a-fA-F]{64}", signature_header, re.ASCII):
return False
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest().encode("ascii")
return hmac.compare_digest(signature_header.lower().encode("ascii"), expected)
Missing, empty, malformed or mismatched signature: respond 401. Express handlers must read the body with express.raw({ type: '*/*' }) so any content type verifies the exact bytes.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Events
Dispatch on the body's top-level eventName field (<object>.<action>); no header names the event. Every delivery is an HTTPS POST with a JSON body shaped { "requestId", "eventName", "date", "payload": { "shopId", ... } }.
| Event | Meaning |
|---|---|
call.created | A call is ringing |
call.queued | A call was queued |
call.answered | A call was answered |
call.closed | A call ended |
conversation.created | A new conversation started |
conversation.replied | A reply was added to a conversation |
conversation.note.added | An internal note was added |
conversation.assigned | A conversation was assigned |
conversation.closed | A conversation was closed |
conversation.reopened | A conversation was reopened |
Delivery and Idempotency
Respond 200 within 5 seconds. Non-2xx responses are retried up to 9 times, with the interval growing by 30 seconds each retry. After 10 consecutive failures within 5 minutes the webhook is disabled until you re-enable it in the Belco dashboard. Dedupe on requestId, and acknowledge quickly and process asynchronously.
Environment Variables
BELCO_WEBHOOK_SECRET=your_webhook_secret # the `secret` property of the Webhook object returned by the API
Setup with Hookdeck
Create the Hookdeck source with the Belco type and paste the webhook's secret into the source's webhook verification settings. Hookdeck verifies x-hook-signature (HMAC-SHA256, hex) and Belco's POST delivery.
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 belco --path /webhooks/belco
Reference Materials
- references/overview.md - Belco webhook concepts, events and payloads
- references/setup.md - Create a webhook through the API and get its secret
- references/verification.md - Signature verification details and gotchas