Skip to content

Receiving webhooks

The Webhook node POSTs a JSON to your address on every alert. That way your own bots, n8n, Zapier or Home Assistant react to your chains. Webhooks are available from the Pro plan and during the trial.

  • Method: POST, only to https addresses, without redirects, timeout 10 seconds.
  • Addresses in your own network (localhost, private IP ranges) are not accepted.
Headers
Content-Type: application/json; charset=utf-8
User-Agent: Bellchain-Webhook/1.0 (+https://bellchain.app)
Bellchain-Event: alert
Bellchain-Delivery: <id of the delivery, the same on retries>
Bellchain-Signature: t=1792243273,v1=9a7a…27cc2
Body
{
"id": "nEkQk4fzMqjbDEndm0N77E",
"type": "alert",
"version": 1,
"test": false,
"time": "2026-10-17T12:00:00.000Z",
"chain": { "id": "chain_456", "name": "BTC Dip Buyer" },
"action": "w1",
"message": "BTC Dip Buyer: RSI 14: 28.7 · Price: $117,234",
"pair": "BTC/USDT",
"price": 117234,
"values": [{ "node": "r1", "pin": "out", "label": "RSI 14", "value": 28.7, "text": "28.7" }]
}

id is always the same for the same action on the same candle, so you can recognize a duplicate request. test is true for test messages.

Bellchain-Signature contains the timestamp t (seconds) and v1, an HMAC-SHA256 over <t>.<body> with your signing secret (whsec_…). In Node.js:

verify.js
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verify(secret, rawBody, header) {
const parts = Object.fromEntries(header.split(',').map((part) => part.split('=')));
// Older than 5 minutes: reject, against replayed requests
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const expected = createHmac('sha256', secret).update(`${parts.t}.${rawBody}`).digest('hex');
return parts.v1?.length === expected.length && timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
}

Verify the signature over the unmodified body as it arrives, before parsing it as JSON.

Respond with a 2xx status as soon as you have accepted the request. On 408, 425, 429, 5xx or network errors Bellchain retries, five attempts in total: right away, after about 5 seconds, 25 seconds, 2 minutes and 10 minutes. If you send a wait time with Retry-After, at least that applies. Other 4xx responses and redirects count as permanently failed.

Muting doesn’t apply to webhooks: they keep running so that your automation misses nothing.