Skip to main content

API docs → Webhooks

Webhooks

Push every detection, plagiarism report, and subscription event to your own server. Plus tier and above. HMAC-SHA256 signed bodies, 7 retries over 72h.

Setting up

  1. Go to your dashboard and open the Webhooks panel.
  2. Add an endpoint URL (must be HTTPS).
  3. Copy the signing secret. Shown once — store it like a password.
  4. Pick the event types you want to subscribe to (defaults to all detection events).

Events

TypeDescription
detection.completedFired after every successful /v1/detect. Body matches the detection response shape.
detection.deep.completedFired after every successful /v1/detect/deep. Body matches the deep-detection response shape.
plagiarism.completedFired after every successful /v1/plagiarism. Body matches the plagiarism response shape.
subscription.activatedFired when a subscription starts or upgrades. Body: { user_id, tier, started_at }.
subscription.canceledFired on cancellation. Body: { user_id, tier, canceled_at, access_until }.
subscription.past_dueFired on failed renewal. Body: { user_id, tier, attempt, next_retry_at }.
balance.lowFired when PAYG / API-only balance falls below $5 USD. Body: { user_id, balance_cents }.

Request shape

Every webhook is a POST with these headers and a JSON body:

POST https://your-app.example.com/dad-webhook
X-DAD-Signature: a8f2e9...           HMAC-SHA256(body, signing_secret) hex
X-DAD-Event:     detection.completed Same as body.type
X-DAD-Delivery:  0190b1f8-...        Stable id — dedupe on this
X-DAD-Timestamp: 1717948800000       Unix-ms; reject deliveries older than 5 min
Content-Type:    application/json

{
  "id":   "evt_01J...",               Stable event id (also in X-DAD-Delivery)
  "type": "detection.completed",
  "created": 1717948800000,
  "api_version": "v1",
  "data": { ... }                    Same shape as the originating endpoint response
}

Verifying signatures

Compute HMAC-SHA256(body, secret) over the raw request body and compare (constant-time) against X-DAD-Signature. Always read the body as raw bytes before any JSON parsing.

Node.js / Express

// Node.js / Express handler — verifies signature then dispatches.
// npm install express
import express from 'express';
import crypto from 'node:crypto';

const app = express();
const WEBHOOK_SECRET = process.env.DAD_WEBHOOK_SECRET; // from your dashboard

// Webhook bodies must be read RAW (not parsed) for signature checking.
app.post('/dad-webhook',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const sigHeader = req.header('X-DAD-Signature') ?? '';
    const expected = crypto
      .createHmac('sha256', WEBHOOK_SECRET)
      .update(req.body)
      .digest('hex');

    // timingSafeEqual to avoid leaking the signature via timing.
    const a = Buffer.from(sigHeader, 'hex');
    const b = Buffer.from(expected, 'hex');
    if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
      return res.status(401).send('bad signature');
    }

    const event = JSON.parse(req.body.toString('utf8'));
    switch (event.type) {
      case 'detection.completed':
        // event.data is the full detection response
        console.log('AI score:', event.data.score, 'band:', event.data.band);
        break;
      default:
        console.log('unhandled event:', event.type);
    }
    // ACK within 10s. We retry on non-2xx for 72h.
    res.status(200).send('ok');
  },
);

app.listen(3000);

Retry policy

If your endpoint returns non-2xx (or times out after 10s), we retry with exponential backoff. After the 7th failed attempt the delivery moves to the dead-letter log and you receive an email alert.

AttemptWait
1Immediate
21 minute
35 minutes
415 minutes
51 hour
66 hours
724 hours
8 (final)72 hours

Webhooks are at-least-once. Use X-DAD-Delivery (or data.id) to dedupe — every retry of the same event ships the same id.

Best practices

  • Respond 2xx within 10s. Do heavy work in a queue, not inline.
  • Reject deliveries with X-DAD-Timestamp more than 5 minutes old to defeat replay.
  • Verify signatures before parsing JSON — never trust the body before HMAC validation.
  • Store the signing secret in a vault. Rotate from the dashboard if you suspect compromise.
  • Use X-DAD-Delivery as an idempotency key in your downstream pipeline.

Webhooks are a Plus feature

Plus, Business, Team, and Enterprise include webhook delivery. Upgrade to receive every detection in real time.

See pricing