Webhooks
TraceIQ Webhooks forward events in real time to external HTTP endpoints as JSON payloads. Manage endpoints, monitor deliveries, inspect failure logs, and test endpoints from the Webhooks page.
Request Headers
Every webhook POST request includes standard metadata headers and an HMAC-SHA256 signature:
X-TraceIQ-Event— The name of the event being delivered (e.g. order_completed, $identify).X-TraceIQ-Delivery-ID— Unique UUID for this specific delivery attempt.X-TraceIQ-Timestamp— Unix timestamp in seconds when the webhook was signed.X-TraceIQ-Signature— HMAC-SHA256 signature in format "sha256=<hex_digest>" computed over `${timestamp}.${rawBody}`.User-Agent— TraceIQ-Webhooks/2.0
Verifying Signatures
To prevent replay attacks and verify authenticity, always verify the signature against the raw request body and timestamp before processing.
Node.js (Express / Fastify):
import crypto from 'crypto';
export function verifyWebhook(rawBody: string, signatureHeader: string, timestampHeader: string, secret: string) {
const [scheme, signature] = signatureHeader.split('=');
if (scheme !== 'sha256' || !signature) return false;
// Prevent replay attacks (tolerance: 5 minutes)
const timestamp = parseInt(timestampHeader, 10);
if (isNaN(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) {
return false;
}
const payloadToSign = `${timestampHeader}.${rawBody}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payloadToSign)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}Python (FastAPI / Flask):
import hmac
import hashlib
import time
def verify_webhook(raw_body: bytes, signature_header: str, timestamp_header: str, secret: str) -> bool:
try:
scheme, signature = signature_header.split('=', 1)
if scheme != 'sha256':
return False
# Check timestamp freshness (5 minutes tolerance)
ts = int(timestamp_header)
if abs(time.time() - ts) > 300:
return False
payload = f"{timestamp_header}.".encode('utf-8') + raw_body
expected = hmac.new(secret.encode('utf-8'), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
except Exception:
return FalseRetry Policy
Deliveries timeout after 10 seconds. On transient failures (HTTP 408, 425, 429, 500, 502, 503, 504, or connection timeouts), TraceIQ automatically retries up to 5 times with exponential backoff:
Attempt 1 → 2— ~60 secondsAttempt 2 → 3— ~5 minutesAttempt 3 → 4— ~30 minutesAttempt 4 → 5— ~2 hours
Client errors (400, 401, 403, 404, 422) are treated as permanent failures and will not be retried automatically. You can always manually retry any delivery from the webhook detail drawer.

