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
- Go to your dashboard and open the Webhooks panel.
- Add an endpoint URL (must be HTTPS).
- Copy the signing secret. Shown once — store it like a password.
- Pick the event types you want to subscribe to (defaults to all detection events).
Events
| Type | Description |
|---|---|
detection.completed | Fired after every successful /v1/detect. Body matches the detection response shape. |
detection.deep.completed | Fired after every successful /v1/detect/deep. Body matches the deep-detection response shape. |
plagiarism.completed | Fired after every successful /v1/plagiarism. Body matches the plagiarism response shape. |
subscription.activated | Fired when a subscription starts or upgrades. Body: { user_id, tier, started_at }. |
subscription.canceled | Fired on cancellation. Body: { user_id, tier, canceled_at, access_until }. |
subscription.past_due | Fired on failed renewal. Body: { user_id, tier, attempt, next_retry_at }. |
balance.low | Fired 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.
| Attempt | Wait |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 1 hour |
| 6 | 6 hours |
| 7 | 24 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-Timestampmore 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-Deliveryas 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