Webhooks
A webhook sends tracker events to your server as they happen. For example, push each new conversion into your CRM at once, or send alerts to an on-call chat. Tab: Automation → Webhooks.

- Add webhook — opens the form with URL, events and secret.
Creating a webhook
Section titled “Creating a webhook”| Field | What to enter |
|---|---|
| Target URL | A public HTTPS address of your server. Local and private addresses are blocked. |
| Events | One or more items from the list below. |
The system generates the secret. It is shown once, right after creation. Copy it then. If it is lost, use “Rotate secret”: the old secret stops working immediately.
Events
Section titled “Events”| Event | When it is sent |
|---|---|
Conversion (conversion) |
A conversion was created or updated, for example a lead became a sale. |
Offer disabled (offer_disabled) |
The system disabled an offer: failed health checks or a CR drop. |
Domain banned (domain_banned) |
A domain was blocked and traffic moved to another domain. |
Alert fired (alert_fired) |
An alert rule fired. |
Request format
Section titled “Request format”POST /your/endpoint HTTP/1.1Content-Type: application/jsonX-Webhook-Event: conversionX-Webhook-Signature: 3f9a…c1d2
{"event":"conversion","data":{...},"timestamp":"2026-10-13T09:15:00.000Z"}data fields per event:
conversion:conversionId,status,payout,currency,clickToken,offerId,isNew.offer_disabled:offerId,name,reason,source(health_checkorcr_threshold).domain_banned:domainId,domain,reason,rotatedTo.alert_fired:ruleName,metric,operator,threshold,value,sampleSize,scope,dimensionValue,action,firedAt.
Verifying the signature
Section titled “Verifying the signature”X-Webhook-Signature is the HMAC-SHA256 of the raw request body, using your secret, as lowercase hex, with no prefix.
Compute the signature over the body exactly as it arrived, not over JSON you parsed and re-serialized. Whitespace and key order change the signature.
import crypto from 'node:crypto';import express from 'express';
const SECRET = process.env.TG_WEBHOOK_SECRET;const app = express();
// You need the raw body, so use express.raw, not express.json.app.post('/telegfy', express.raw({ type: 'application/json' }), (req, res) => { const expected = crypto.createHmac('sha256', SECRET).update(req.body).digest('hex'); const received = req.get('X-Webhook-Signature') ?? ''; const ok = received.length === expected.length && crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected)); if (!ok) return res.status(401).end();
const event = JSON.parse(req.body.toString('utf8')); // process idempotently: see "Retries" below res.status(200).end();});import hmac, hashlib, jsonfrom flask import Flask, request, abort
SECRET = b"your-secret"app = Flask(__name__)
@app.post("/telegfy")def telegfy(): raw = request.get_data() # raw body, not parsed expected = hmac.new(SECRET, raw, hashlib.sha256).hexdigest() received = request.headers.get("X-Webhook-Signature", "") if not hmac.compare_digest(received, expected): abort(401) event = json.loads(raw) return "", 200Delivery and retries
Section titled “Delivery and retries”- A request counts as delivered when your server answers 2xx within 5 seconds.
- Otherwise it is retried after 1, 5, 15 and 60 minutes. 5 attempts in total; after that the delivery is marked as failed.
- A retry can arrive after you already processed the event (for example, when the response was lost on the network). Process events idempotently, for example by the key
event + conversionIdorevent + ruleName + firedAt.
Access
Section titled “Access”Owners, admins and editors create, change and delete webhooks. Viewers see the list.
/api/v1/webhooks — user session (JWT) only. API keys are not allowed. The secret is returned once, on creation and on rotation.
Related
Section titled “Related”- Alert rules — what triggers
alert_fired. - Notification channels — another way to receive alerts, without a signature.