DocsWebhooks
Reference

Webhooks

Receive a signed POST request to any HTTPS endpoint whenever Nixer detects new critical or high findings in a connected repo.

Plan gating: Generic webhooks require Pro or Team. Slack webhooks are available on Starter+. Configure both at /app/integrations →

Event: scan.new_findings

Fired once per scan when at least one new critical or high finding is detected that was not present on the previous scan of the same repo.

Payload schema (version 1)

{
  "event": "scan.new_findings",
  "version": "1",
  "timestamp": "2026-06-08T18:30:00.000Z",
  "scan_id": 12345,
  "repo_url": "https://github.com/your-org/your-repo",
  "scan_url": "https://nixer.polsia.app/app/scans/12345",
  "new_findings": {
    "critical": 2,
    "high": 5,
    "total": 7
  },
  "top_findings": [
    {
      "rule_id": "prompt-injection",
      "severity": "critical",
      "title": "Direct prompt injection in user-facing chain",
      "file": "src/chains/user_query.py",
      "line": 42,
      "description": "LLM receives raw user input without sanitization or trust boundary."
    },
    {
      "rule_id": "hardcoded-secret",
      "severity": "high",
      "title": "OpenAI API key hardcoded in source",
      "file": "config/settings.py",
      "line": 17,
      "description": "API key detected in plaintext — rotate immediately."
    }
  ]
}

Test event payload

When you click Test on an integration, we send this instead of a real finding alert:

{
  "event": "test",
  "version": "1",
  "timestamp": "2026-06-08T18:30:00.000Z",
  "message": "Nixer webhook connection test — your integration is working correctly."
}

Signature verification

If you configure a secret on your webhook integration, every request includes:

X-Nixer-Signature: sha256=<hex digest>

The digest is an HMAC-SHA256 of the raw request body using your secret as the key. Verify it before processing the event:

Node.js

const crypto = require('crypto');

function verifySignature(secret, rawBody, signatureHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signatureHeader)
  );
}

// Express example
app.post('/webhooks/nixer', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-nixer-signature'];
  if (!verifySignature(process.env.NIXER_WEBHOOK_SECRET, req.body, sig)) {
    return res.status(401).send('Bad signature');
  }
  const event = JSON.parse(req.body);
  console.log('Nixer event:', event.event, 'scan:', event.scan_id);
  res.sendStatus(200);
});

Python

import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SECRET = os.environ['NIXER_WEBHOOK_SECRET'].encode()

@app.route('/webhooks/nixer', methods=['POST'])
def handle():
    sig = request.headers.get('X-Nixer-Signature', '')
    expected = 'sha256=' + hmac.new(SECRET, request.data, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        abort(401)
    event = request.get_json()
    print('Nixer event:', event['event'], 'scan:', event.get('scan_id'))
    return '', 200

Delivery & retry

Nixer attempts delivery up to 3 times with exponential backoff:

AttemptDelay from previous failure
1Immediate (fires after scan completes)
230 seconds
35 minutes

We consider a delivery successful when your endpoint returns any 2xx HTTP status. After 3 failures the attempt is marked failed and no further retries occur for that event. The last 20 delivery attempts are visible on the integration card at /app/integrations.

Integration settings

SettingValuesDescription
severity_filtercriticals_and_highs (default)
criticals_only
Which severity levels trigger an alert.
muted_repo_urlsOne URL per lineRepos for which alerts are silenced.

Schema stability

The payload schema is versioned. The current version is 1 (the version field). We will increment this version and provide migration guidance before making breaking changes. Additive fields (new top-level keys) may be added without a version bump.