Skip to main content

What this is

Webhooks are a Premium-tier-only push channel. Instead of polling /v1/arb/live or holding a WebSocket connection open, you give us an HTTPS URL and we POST the same opportunity payload to you the moment the engine detects it — typically within ~100 ms of the underlying snapshot arriving. Use this if you’d rather not run a persistent process to receive signals. A serverless function (Cloudflare Worker, Vercel function, Lambda) wakes up only when a real signal fires.

Registering a webhook

  1. Open /dashboard/webhooks.
  2. Click Create webhook.
  3. Fill in:
    • URLhttps://your-domain.com/webhook (must be HTTPS)
    • Label — anything memorable, e.g. prod-bot
    • Tier filterlogical, endgame, or both
    • Ticker filter — subset of BTC, ETH, SOL (omit for all)
  4. The success callout shows the signing secret ONCE (starts with whsec_…). Save it. You can’t retrieve it later — if you lose it, delete the webhook and recreate.

What each POST looks like

Header reference

Body fields

Verifying the signature

Always verify. Without the check, anyone with your URL could POST fake opportunities. The signature is a hex-encoded HMAC-SHA256 over the raw request body bytes (not the parsed JSON) using your secret as the key.

Delivery semantics

  • Timeout: 5 seconds. Reply 2xx within that or we treat the delivery as failed.
  • Auto-pause: 10 consecutive failures → the webhook is paused. You’ll see it in /dashboard/webhooks with a “Failing” badge; click Resume once your endpoint is back.
  • Idempotency: Each opportunity carries a unique (market_id, detected_at) pair. We may re-fire the same opportunity if our worker restarts; deduplicate on that pair if your downstream isn’t idempotent.
  • At-least-once: Treat the delivery as at-least-once, not exactly-once. The Redis pub/sub channel + the retry loop means a single fire event can land twice in rare cases.
  • No backfill on register: If signals fired before you created the webhook, you won’t get them later. Use GET /v1/arb/live to catch up on currently-actionable signals.

Quick local testing

The simplest test setup needs no servers:
  1. Open webhook.site — you get a unique URL like https://webhook.site/abc-….
  2. Paste that URL into the create-webhook form.
  3. Leave both tabs open. When an opportunity fires, you’ll see the POST appear in real time on webhook.site.
For development against your own code, use ngrok to expose localhost:

Common mistakes

  • Parsing the body before verifying the signature — most web frameworks parse JSON middleware-style. The signature is over the raw bytes, so middleware that re-serializes the body breaks verification. Capture raw bytes first, verify, then parse.
  • HTTP, not HTTPS — we reject http:// URLs at registration time. Signatures don’t replace TLS; both matter.
  • Replying slowly — if your handler does heavy work synchronously, we may timeout before you ack. Acknowledge immediately, do the work in the background.
  • No tier check downstream — we deliver to webhooks registered when the user was on Premium even if they later downgrade (we re-check tier at register time only). If you build a multi-tenant system on top, gate at your own layer too.

Pricing

Webhook alerts are included with the Premium plan. Free / Pro / Plus users can register webhooks via the dashboard but registration returns 403. See pricing.