Docs / Reference / Webhooks

Webhooks

Subscribe to signed outbound webhooks for scan.completed and credits.low, and verify the signature before trusting a delivery.

Webhooks push events to your systems so you don’t have to poll. Create a subscription with a delivery URL, and AskThis sends a signed POST whenever a subscribed event fires.

You can manage subscriptions two ways: in the dashboard under Developers (create, pause, send a test, delete — the signing secret is shown once at creation), or over the API as shown below.

Events

EventFires when
scan.completedAn onboarding or re-scan finishes and prompts are ready
scan.failedA scan job errors out
credits.lowYour credit balance drops below the low-balance threshold
credits.depletedYour credit balance hits zero — act now (top up or upgrade)
citation.detectedA Citation Monitor run finds your site cited by an AI engine
subscription.updatedYour plan changes — created, upgraded, downgraded or cancelled
invoice.paidA gateway invoice is paid
site.installedA site’s widget is verified live for the first time

Subscribe to any subset. Subscribing to an event name outside this list is rejected with a 422.

Example payloads

// credits.depleted
{ "event": "credits.depleted", "payload": { "orgId": "org_...", "balance": 0 },
  "timestamp": "2026-07-15T09:00:00.000Z" }

// citation.detected
{ "event": "citation.detected",
  "payload": { "siteId": "cq_8f2a", "cited": 3, "total": 6, "engines": ["chatgpt", "gemini"] },
  "timestamp": "2026-07-15T09:00:00.000Z" }

// subscription.updated
{ "event": "subscription.updated",
  "payload": { "orgId": "org_...", "plan": "business", "status": "active", "cancelled": false },
  "timestamp": "2026-07-15T09:00:00.000Z" }

Subscribing

# Create a subscription → the signing secret is returned ONCE
curl -X POST https://api.askthis.io/api/v1/webhook-subscriptions \
  -H "Authorization: Bearer <session>" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.yoursite.com/askthis",
    "events": ["scan.completed", "credits.low"]
  }'

# List subscriptions (the secret is never shown again)
curl https://api.askthis.io/api/v1/webhook-subscriptions -H "Authorization: Bearer <session>"

# Delete a subscription
curl -X DELETE https://api.askthis.io/api/v1/webhook-subscriptions/<id> \
  -H "Authorization: Bearer <session>"

Verifying deliveries

Every delivery is signed with HMAC-SHA256 over the raw request body, using your subscription secret. The hex signature arrives in the X-AskThis-Signature header. Recompute it and compare before trusting the payload:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, header, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(expected);
  const b = Buffer.from(header ?? "");
  return a.length === b.length && timingSafeEqual(a, b);
}

// Express example (raw body required)
app.post("/askthis", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.get("X-AskThis-Signature"), process.env.ASKTHIS_WEBHOOK_SECRET)) {
    return res.status(401).end();
  }
  const event = JSON.parse(req.body.toString());
  // handle event.type: "scan.completed" | "credits.low"
  res.status(200).end();
});

Test & debug

Verify a subscription without waiting for a real event — send a sample signed ping:

curl -X POST https://api.askthis.io/api/v1/webhook-subscriptions/<id>/test \
  -H "Authorization: Bearer <session>"
# → { "data": { "delivered": true, "status": "200" }, ... }

And inspect the recent delivery attempts (newest first) to debug failures:

curl https://api.askthis.io/api/v1/webhook-subscriptions/<id>/deliveries \
  -H "Authorization: Bearer <session>"
# → [{ "event": "scan.completed", "status": "200", "at": "..." }, ...]

Delivery guarantees

  • Signed — always verify the signature; reject on mismatch.
  • Time-boxed — each delivery attempt times out after 5 seconds, so respond fast (queue the work, return 200).
  • Retried — failed deliveries are retried, so make your handler idempotent (dedupe on the event ID).

See also: API keys for authenticating the management calls above.