Webhooks.
Get notified in real time when scans complete. Register webhook URLs and AppVet will POST results to your endpoint as soon as they are ready.
Register a webhook
Send a POST request with the URL to receive events and the
event types you want to subscribe to:
curl -X POST https://appvet.dev/api/webhooks \
-H "Authorization: Bearer avk_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/webhooks/appvet",
"events": ["scan.completed", "scan.failed"]
}' Response:
{
"id": "wh_abc123",
"url": "https://example.com/webhooks/appvet",
"events": ["scan.completed", "scan.failed"],
"secret": "whsec_k7J2mN9xR4pQ1vL8...",
"created_at": "2026-03-31T12:00:00Z"
}
The secret is shown only once at creation. Save it
immediately — you will need it to verify webhook signatures.
Events
| Event | Description |
|---|---|
scan.completed | Scan finished successfully with a full report. |
scan.failed | Scan could not complete (target unreachable, timeout, etc.). |
scan.partial | Scan finished with partial results (some checks could not run). |
Webhook payload
AppVet sends a POST request to your URL with a JSON body:
{
"event": "scan.completed",
"timestamp": "2026-03-31T12:05:00Z",
"data": {
"scan_id": "scan_abc123",
"url": "https://example.com",
"type": "security",
"status": "completed",
"score": 84,
"grade": "A-",
"findings_count": 5,
"report_url": "https://appvet.dev/report/scan_abc123"
}
} Signature verification
Every webhook request includes an
X-AppVet-Signature header containing an HMAC-SHA256
signature of the request body, signed with your webhook secret. Always
verify this signature to ensure the request is authentic.
The signature format is: sha256=<hex-digest>
Node.js verification example
import crypto from "crypto";
function verifySignature(body, signature, secret) {
const expected = "sha256=" +
crypto.createHmac("sha256", secret)
.update(body, "utf-8")
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your webhook handler:
app.post("/webhooks/appvet", (req, res) => {
const signature = req.headers["x-appvet-signature"];
const isValid = verifySignature(
req.body, // raw request body string
signature,
process.env.APPVET_WEBHOOK_SECRET // whsec_...
);
if (!isValid) {
return res.status(401).send("Invalid signature");
}
const event = JSON.parse(req.body);
console.log(event.event, event.data.scan_id, event.data.score);
res.status(200).send("OK");
}); List webhooks
curl https://appvet.dev/api/webhooks \
-H "Authorization: Bearer avk_live_your_key_here"
# Response:
# [
# { "id": "wh_abc123", "url": "https://...", "events": [...] },
# { "id": "wh_def456", "url": "https://...", "events": [...] }
# ] Delete a webhook
curl -X DELETE https://appvet.dev/api/webhooks/wh_abc123 \
-H "Authorization: Bearer avk_live_your_key_here"
# Response: 204 No Content Next steps
- GitHub Action — scan on every pull request with automatic PR comments.
- Score Badges — embed live score badges in your README.
- API Reference — full endpoint documentation for scans, reports, and usage.