Webhook Integration
Receive real-time notifications when scans complete or vulnerabilities are found.
How Webhooks Work
- 1Submit a scan with a webhook URL - Include your endpoint in the API request
- 2MCPSafe processes the scan - Analysis runs in the background
- 3Webhook is triggered - POST request sent to your URL with results
Submitting a Scan with Webhook
API Request
Include the webhook parameter when submitting a scan
curl -X POST https://api.mcpsafe.org/api/v1/scans/url \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"url": "https://github.com/owner/repo",
"webhook": "https://your-server.com/webhook/mcpsafe"
}'Webhook Events
scan.completed
Fired when a scan finishes successfully
scan.failed
Fired when a scan encounters an error
vulnerability.found
Fired for each critical/high vulnerability (Pro+)
Payload Example
scan.completed Event
Example payload sent to your webhook endpoint
{
"event": "scan.completed",
"timestamp": "2024-01-15T10:30:45Z",
"data": {
"scanId": "scan_abc123xyz",
"url": "https://github.com/owner/repo",
"status": "completed",
"results": {
"securityScore": 72,
"grade": "B",
"vulnerabilities": {
"critical": 0,
"high": 1,
"medium": 2,
"low": 3,
"info": 5,
"total": 11
}
},
"reportUrl": "https://mcpsafe.org/scan/scan_abc123xyz"
}
}Signature Verification
Verifying Webhook Signatures
Always verify the X-MCPSafe-Signature header to ensure webhooks are authentic
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expectedSignature}`)
);
}
// Express.js example
app.post('/webhook/mcpsafe', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-mcpsafe-signature'];
const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = JSON.parse(payload);
console.log('Received webhook:', event.event);
// Handle the event
switch (event.event) {
case 'scan.completed':
handleScanCompleted(event.data);
break;
case 'scan.failed':
handleScanFailed(event.data);
break;
}
res.status(200).json({ received: true });
});Security Warning
Always verify webhook signatures before processing. Never trust the payload without verification.
Best Practices
Respond Quickly
Return 2xx within 30 seconds or we'll retry
Use HTTPS
Webhook URLs must use HTTPS for security
Handle Duplicates
Same event may be sent multiple times on retry
Process Async
Queue events for background processing
Retry Policy
If your endpoint doesn't respond with a 2xx status code, we'll retry:
- 1Immediately after failure
- 21 minute later
- 35 minutes later
- 430 minutes later (final attempt)