Webhooks

Get a signed HTTP POST the moment Redditoro drafts a new lead, then pipe it into n8n, Zapier, Slack, a database, or your own service. This is a plain HTTP integration; you don't need MCP or any client to use it.

How it works

Redditoro scans Reddit for your keywords around the clock. Whenever a scan drafts a new lead for a project, we immediately send an HTTP POST to every active webhook URL on that project. The body is JSON and carries the full lead, so your system can act on it without calling our API back.

Webhooks are scoped per project and available on Growth and up. Each webhook has its own signing secret so you can verify that a request really came from us.

Add a webhook

  1. Switch to the project you want, then open MCP / API access in the dashboard.
  2. In the Webhooks card, paste your endpoint URL (must be https://) and click Add.
  3. Copy the signing secret shown once. Store it as an env var; you'll use it to verify every request. You can delete a webhook any time to stop delivery.

Events

EventFires when
lead.createdA scan drafts a new lead (a matched Reddit post/comment with a generated reply) for the project.

More events (published, outcome changes) are on the roadmap. Ignore events you don't recognise so new ones never break your handler.

Payload

POST /your/endpoint  HTTP/1.1
Content-Type: application/json
User-Agent: Redditoro-Webhooks/1.0
X-Redditoro-Signature: sha256=3b8f...c1

{
  "event": "lead.created",
  "created_at": "2026-03-14T10:02:00.000Z",
  "data": {
    "subreddit": "SaaS",
    "title": "Best tool to find leads on Reddit?",
    "url": "https://www.reddit.com/r/SaaS/comments/abc123/best_tool/",
    "leadScore": 4,
    "product": "Redditoro",
    "reply": "honestly just used redditoro for this, worked well even on..."
  }
}

Fields

FieldTypeDescription
eventstring"lead.created"
created_atstringISO 8601 timestamp of when we sent it
data.subredditstring | nullSubreddit the lead is in (no r/ prefix)
data.titlestringTitle of the Reddit thread
data.urlstringFull permalink to the post or comment
data.leadScorenumberBuying-intent score, 1 (cold) to 5 (hot)
data.productstringWhich of your products it was matched to
data.replystringThe AI-drafted reply awaiting your review

Verify the signature

Every request includes an X-Redditoro-Signature header of the form sha256=<hex>. It's an HMAC-SHA256 of the raw request body keyed with your webhook secret. Recompute it and compare in constant time; reject anything that doesn't match.

import crypto from "crypto";

// Express example. IMPORTANT: verify against the RAW request body, not a
// re-serialised object — re-stringifying changes bytes and breaks the check.
app.post("/hooks/redditoro", express.raw({ type: "application/json" }), (req, res) => {
  const signature = req.header("X-Redditoro-Signature") || "";
  const expected =
    "sha256=" + crypto.createHmac("sha256", process.env.REDDITORO_WEBHOOK_SECRET)
      .update(req.body)            // req.body is a Buffer (the raw bytes)
      .digest("hex");

  const ok =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  if (!ok) return res.status(401).send("bad signature");

  const event = JSON.parse(req.body.toString());
  // ...handle event.data, then:
  res.sendStatus(200);
});

Python:

import hmac, hashlib

def verify(raw_body: bytes, header: str, secret: str) -> bool:
    expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(header, expected)

Delivery & retries

  • One POST per new lead. A scan that finds several leads sends several requests.
  • We wait up to 5 seconds for a response. Return a 2xx quickly and do slow work asynchronously, or you may time out.
  • Delivery is best-effort with no automatic retries yet: if your endpoint is down or slow, that event is missed. Treat webhooks as a fast notification, not a system of record, and reconcile with the list_leads tool if you need guaranteed completeness.
  • Events may arrive out of order and, rarely, more than once. Make your handler idempotent (the post URL is a good dedupe key).

Testing locally

Point a webhook at webhook.site (or an ngrok tunnel to your machine) to inspect real payloads, then run a scan from the dashboard or the run_scan tool to trigger one.

Security checklist

  • Only accept https:// endpoints and always verify the signature.
  • Compare signatures in constant time (timingSafeEqual / compare_digest).
  • Keep the secret server-side; rotate it by deleting and re-adding the webhook.
  • Don't trust the payload blindly; it's an AI-drafted reply you still review before publishing.