Webhooks
Receive signed JSON events for conversions, offers, partner sign-ups and access requests, and verify them.
Last updated 3 min read
On this page
Webhooks push events from your workspace to your own systems — a CRM, a data warehouse, Zapier — as signed JSON
POST requests. Unlike partner postbacks (one URL per partner, with macros), a webhook receives a fixed JSON
document for every event it subscribes to.
Events#
Events are queued in the same database transaction as the change, so a committed change is never missed.
Create a webhook#
- Go to Automation → Webhooks (
/app/automation/webhooks). - Click New webhook.
- Enter a Name and the Endpoint URL — a public
http(s)URL without credentials, IP address or internal host name. - Tick the Events.
- Keep Active checked and click Save webhook.
A workspace can have up to 50 webhooks. Open a webhook to see its URL, the Signing secret (admins only), the delivery log, Edit, Rotate secret and Delete.
Request format#
POST /hooks/conversions HTTP/1.1
Content-Type: application/json
User-Agent: ArcTrack-Webhook/1.0
X-ArcTrack-Event: conversion.created
X-ArcTrack-Delivery: 81723
X-ArcTrack-Timestamp: 1760262000
X-ArcTrack-Signature: t=1760262000,v1=5f2b…c9The ArcTrack-Webhook/1.0 user agent and the X-ArcTrack-… header names are fixed technical identifiers of the
tracking engine — the same on every installation, whatever the brand.
{
"id": "1b7e8c2a-4f0d-4e57-9a3b-0c6d2e1f8a90",
"event": "conversion.created",
"workspace_id": 1,
"created_at": "2026-10-12T09:40:00.000Z",
"data": {
"id": "5f0c2a8e-1d3b-4c6e-9f7a-2b8d4e6f1a3c", "click_id": "0192f3c1a2b4e1f0c9d84b2a7e6f5d3c",
"offer_id": 12, "affiliate_id": 7, "advertiser_id": 3, "event": "sale", "status": "approved",
"status_reason": "", "revenue": "10.0000", "payout": "6.0000", "sale_amount": "49.9000", "currency": "USD",
"adv_txid": "ORDER-1001", "method": "s2s", "conv_ts": "2026-10-12T09:40:00.000Z",
"click_ts": "2026-10-12T09:12:44.120Z", "sub1": "summer", "sub2": "", "sub3": "", "sub4": "", "sub5": "",
"source_id": "", "gclid": "", "country": "US", "device_type": "mobile"
}
}id is unique per event — use it to ignore repeats. Money is a 4-decimal string; times are ISO-8601 UTC.
conversion.updated adds "previous": {"status", "revenue", "payout", "sale_amount"}. Test events carry
"test": true.
Verify the signature#
The X-ArcTrack-Signature header is t=<unix seconds>,v1=<hex HMAC-SHA256(secret, "<t>.<raw body>")>. Verify it on the
raw body and reject timestamps older than a few minutes:
// Node.js
import crypto from "node:crypto";
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false; // replay window
const mac = crypto.createHmac("sha256", secret).update(parts.t + "." + rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(parts.v1));
}# Python
import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=", 1) for p in header.split(","))
if abs(time.time() - int(parts["t"])) > 300:
return False
mac = hmac.new(secret.encode(), parts["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(mac, parts["v1"])Rotate secret generates a new secret; deliveries are signed with it immediately.
Delivery and retries#
Deliveries can arrive out of order and, after a retry, more than once: process them idempotently by id.
Test and retry#
- On the webhook page, under Send a test event, choose an event and click Send test event. A delivery with sample data appears in the log within seconds (marked Test).
- In the delivery log, select rows and use Retry to queue them again.