Integration guide
Gjall can POST a JSON payload to any HTTPS endpoint when a vendor alert is detected. Use webhooks to route alerts into your own systems, trigger automations, or fan out to services not natively supported.
Tip: Gjall retries failed deliveries up to 3 times with exponential backoff. Your endpoint should return a 2xx status to acknowledge receipt.
Every webhook delivery sends a POST with Content-Type: application/json.
{
"event": "alert.created",
"vendor": "Stripe",
"severity": "high",
"type": "cve",
"title": "CVE-2025-12345 in Stripe API library",
"description": "A reflected XSS vulnerability was found in ...",
"source_url": "https://nvd.nist.gov/vuln/detail/CVE-2025-12345",
"detected_at": "2025-06-09T03:15:22Z",
"customer_id": "cust_abc123"
}Every request includes a X-Gjall-Signature header containing an HMAC-SHA256 signature of the raw request body. Always verify this before processing the payload.
import hashlib
import hmac
import os
WEBHOOK_SECRET = os.environ["GJALL_WEBHOOK_SECRET"]
def verify_signature(body: bytes, signature_header: str) -> bool:
"""Return True if the request is from Gjall."""
expected = "sha256=" + hmac.new(
WEBHOOK_SECRET.encode(),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature_header)
# Flask example
from flask import Flask, request, abort
app = Flask(__name__)
@app.post("/gjall-webhook")
def gjall_webhook():
sig = request.headers.get("X-Gjall-Signature", "")
if not verify_signature(request.data, sig):
abort(401)
event = request.json
print(f"Alert: {event['title']} — {event['vendor']} ({event['severity']})")
return {"ok": True}import crypto from "crypto"
const WEBHOOK_SECRET = process.env.GJALL_WEBHOOK_SECRET!
function verifySignature(body: Buffer, signatureHeader: string): boolean {
const expected =
"sha256=" +
crypto.createHmac("sha256", WEBHOOK_SECRET).update(body).digest("hex")
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
)
}
// Express example
import express from "express"
const app = express()
app.post("/gjall-webhook", express.raw({ type: "*/*" }), (req, res) => {
const sig = req.headers["x-gjall-signature"] as string ?? ""
if (!verifySignature(req.body as Buffer, sig)) {
return res.status(401).json({ error: "Invalid signature" })
}
const event = JSON.parse(req.body.toString())
console.log(`Alert: ${event.title} — ${event.vendor} (${event.severity})`)
res.json({ ok: true })
})| Header | Value |
|---|---|
| Content-Type | application/json |
| X-Gjall-Signature | sha256=<hex-digest> |
| X-Gjall-Event | alert.created |
| User-Agent | Gjall-Webhook/1.0 |