Webhooks

Sigmate POSTs every premium signal to your endpoint as soon as it fires. Each request is signed with an HMAC you can verify. Available on Pro and Alpha.

Setup#

  1. Open /dashboard/delivery and configure the Webhook card with your HTTPS URL.
  2. Copy the generated secret. It is shown once, then hashed on our side. Store it in your secret manager.
  3. Send the test ping and confirm your endpoint returns 2xx quickly. Sigmate treats any non-2xx response as a failure and records it on the dashboard.

Request format#

  • Method. POST
  • Content-Type. application/json
  • X-Sigmate-Signature. sha256=<hex>. Hex is the HMAC-SHA256 of the raw request body using your webhook secret.
  • X-Sigmate-Event. Always signal.fired in v1.
  • User-Agent. Sigmate-Webhook/1

Example payload#

The body schema matches the API stream signal frame. A trimmed example:

{
  "id": "f3c7a1d2-8b4e-4d5f-9f2a-6e1c0d7a8b9f",
  "detected_at": "2026-04-24T09:32:14.117Z",
  "signal_type": "consensus_buy",
  "rank": "A",
  "rank_score": 82,
  "token": {
    "address": "7GCihgDB8fe6KNjn2MYtkzZcRjQy3t9GHdC8uHYmW2hr",
    "symbol": "WIF",
    "name": "dogwifhat",
    "dex": "Raydium",
    "market_cap_usd": 412000,
    "liquidity_usd": 88300,
    "price_usd": 0.0069
  },
  "wallet_count": 6,
  "pool_wallet_count": 4,
  "rug_check": {
    "risk": "low"
  },
  "latency_ms": 388
}

Verifying the signature#

Always verify the HMAC before trusting the payload. An attacker who learns your endpoint URL cannot forge a request without the secret.

Node.js / TypeScript

import crypto from "node:crypto";

const SECRET = process.env.SIGMATE_WEBHOOK_SECRET!;

// Inside your POST handler.
export function verifySigmate(req: Request, rawBody: string): boolean {
  const header = req.headers.get("x-sigmate-signature") ?? "";
  const match = header.match(/^sha256=([a-f0-9]{64})$/i);
  if (!match) return false;
  const expected = crypto
    .createHmac("sha256", SECRET)
    .update(rawBody)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(match[1], "hex"),
  );
}

Python

import hmac, hashlib, re

SECRET = os.environ["SIGMATE_WEBHOOK_SECRET"].encode("utf-8")

def verify_sigmate(request) -> bool:
    header = request.headers.get("x-sigmate-signature", "")
    match = re.match(r"^sha256=([a-f0-9]{64})$", header, flags=re.I)
    if not match:
        return False
    expected = hmac.new(SECRET, request.body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, match.group(1))

Use the raw body

You must compute the HMAC over the exact raw bytes of the request body, not a re-serialized JSON object. If your framework parses JSON before your handler runs, reach for the raw-body middleware or equivalent before verifying.

Retries and idempotency#

  • On non-2xx or timeout, Sigmate retries up to 3 times with a short backoff. After that, the failure is recorded on your dashboard and the signal is dropped from the webhook channel (other channels you have enabled are unaffected).
  • Every payload carries a unique id. Deduplicate on that field if your handler is not idempotent by construction.
  • Timeouts: Sigmate closes the connection after 5 seconds. Keep your handler fast, or offload heavy work to a queue and 2xx immediately.

Rotating the secret#

On the delivery page, click Rotate secret. The new secret is shown once, the old one stops being accepted immediately. Re-deploy your endpoint with the new value before rotating to avoid missed verifications.

Disabling#

Toggle the Webhook card off to pause delivery without deleting the configuration. Turn it back on and signals resume within a few seconds.