Honeypot Webhooks: Send Attack Detections to Any API
Version 1.3.0 of the ReportedIP Honeypot Server, released on 12 June 2026, turns its webhooks into a configurable router that sends every attack detection to any HTTP API. Each endpoint sets its own method, headers and body, so detections reach a SIEM, Slack, Discord or AbuseIPDB without extra glue code.
The current release is 1.4.1 from 15 September 2026, and everything described here works the same way in it. Installation and the complete field list are in the Honeypot Server documentation.
What do honeypot webhooks do?
A webhook is an HTTP or HTTPS endpoint that receives a request whenever the honeypot flags an attack that matches the webhook’s filters. The feature arrived in version 1.2.0 with a fixed JSON format for logging and SIEM systems. Version 1.3.0 opened it to any API: Splunk, Elastic, a Slack or Discord channel, or a second abuse database.
The honeypot sends webhooks after the trap response has gone back to the attacker, so a slow or broken endpoint never delays what the attacker sees. When 1.3.0 shipped, the detection pipeline ran 36 analyzers, from SQL injection and cross-site scripting to path traversal and brute force. Since version 1.3.10 it runs 40, and any of them can trigger a webhook.
How do you send honeypot detections to any API?
Up to version 1.2.1 every delivery was a JSON POST. Since 1.3.0 each webhook defines its own request:
- HTTP method:
POST,PUT,PATCHorGET. A GET request carries no body, the data goes into the URL instead. - Custom headers: one per line, for API keys and authentication. They override the default headers.
- Body format: structured
json, URL-encodedformor a freecustomtemplate. - Placeholders: 13 fields such as
{{ip}},{{categories}},{{severity}}and{{timestamp}}, usable in the body and in the URL. Each field also exists as{{..._url}}(URL-encoded) and{{..._json}}(JSON-escaped).
When one request trips several analyzers, each webhook still receives a single delivery. The placeholder fields merge the categories, keep the highest severity and join the comments. The JSON format lists every detection separately.
The AbuseIPDB mapping is built in
Every threat database numbers its categories differently, so reporting to a second one used to need custom mapping code. The {{abuseipdb_categories}} placeholder does the mapping: IDs 1 to 23 are identical on both platforms, and ReportedIP categories from 24 upward are translated to their closest AbuseIPDB equivalent. In 1.3.0 the mapping covered IDs 24 to 58. Since version 1.3.7 it also covers the honeypot categories 59 to 63. A report to the AbuseIPDB report endpoint looks like this:
POST https://api.abuseipdb.com/api/v2/report
Key: <your-abuseipdb-api-key>
Accept: application/json
ip={{ip_url}}&categories={{abuseipdb_categories}}&comment={{comment_url}}
Four presets fill in the request
The webhook form offers four quick presets. Each one fills in URL, method, headers and body template. You then add your own API key or webhook URL.
| Preset | Method | Body format |
|---|---|---|
| Generic JSON | POST | json |
| AbuseIPDB | POST | custom |
| Slack | POST | custom |
| Discord | POST | custom |
The test button sends a delivery with the loopback address 127.0.0.1. Abuse databases reject that address, so testing an AbuseIPDB webhook never files a report against a real host.
How do you set up a webhook?
Webhooks are managed in the honeypot admin panel under Webhooks. The update to 1.3.0 extends the stored webhook settings on its own, no manual migration is needed. Three settings decide what an endpoint receives:
- Category filter: IDs from the threat category list used across ReportedIP.
- Analyzer filter: names of detection engines, for example
SqlInjection. - Secret: optional. It adds an HMAC-SHA256 signature to every request.
With both filters empty, every detection is delivered. With both set, a detection that matches either one triggers the webhook. The panel shows the last status, its time and the number of consecutive failures for each endpoint, and a successful delivery resets that number. The webhook reference lists every field.
What does the default JSON payload look like?
With the json format each request carries Content-Type: application/json, an X-ReportedIP-Event header with the value detection or test and, when a secret is set, an X-ReportedIP-Signature header. The body groups the honeypot, the request and one or more detections:
{
"event": "detection",
"generated_at": "2026-06-12T14:00:00+00:00",
"honeypot": {
"name": "reportedip-honeypot-server",
"version": "1.3.0",
"host": "your-honeypot.example.com",
"profile": "wordpress"
},
"request": {
"ip": "203.0.113.50",
"method": "POST",
"uri": "/wp-login.php",
"user_agent": "sqlmap/1.7"
},
"detections": [
{
"analyzer": "SqlInjection",
"categories": [16, 45],
"category_names": ["SQL Injection", "WP Database Injection"],
"comment": "SQL injection attempt detected: ...",
"severity": 85
}
]
}
Verify the signature on the receiving side
The signature is an HMAC-SHA256 over the raw request body, keyed with your secret (RFC 2104), and arrives as sha256=<hex>. Compute the same value on your side and compare the two in constant time:
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $secret);
$valid = hash_equals($expected, $_SERVER['HTTP_X_REPORTEDIP_SIGNATURE'] ?? '');
Hash the raw bytes before any JSON parsing. A parsed and re-encoded body can differ in whitespace or key order, and the signature no longer matches. GitHub signs its webhooks in the same sha256= format, so existing receiver code only needs a different header name.
Why send honeypot detections to a SIEM?
A honeypot is only useful if someone sees what it catches. Without webhooks, its detections sat in a separate admin panel, away from every other security signal. With webhooks they land next to firewall, WAF and application logs as structured fields you can correlate, alert on or feed into a blocklist. The same detection can go to ReportedIP and to AbuseIPDB at once.
Webhooks also suit server fleets. If you run several servers, as described in the guide on securing a server cluster, one honeypot can feed a central collector that the rest of the cluster reads from.
What changed in versions 1.2.0 to 1.3.0?
Versions 1.2.0, 1.2.1 and 1.3.0 all shipped on 12 June 2026. 1.2.0 introduced webhooks and fixed three problems: Cloudflare IPv6 ranges were missing from client IP detection, the header analyzer flagged legitimate IPv6 addresses as loopback, and reports the API had rejected for good blocked the report queue.
1.2.1 was a hotfix for an HTTP 500 error on the Webhooks page right after the update, caused by an outdated autoloader. 1.3.0 rebuilt delivery into the router described above, added the AbuseIPDB mapping and the presets, merged multiple detections per request and brought the test suite to 363 tests.
Since then, 1.3.1 corrected the help text and the presets on the Webhooks page on the same day, 1.3.3 added the honeypot categories 59 to 63, and 1.3.7 aligned the AbuseIPDB mapping with the corrected category names. If you still run an older build, update straight to 1.4.1.
Honeypot webhooks FAQ
Can the honeypot report to AbuseIPDB?
The honeypot reports to AbuseIPDB through its built-in preset. The preset sets the report endpoint, a custom body template and the {{abuseipdb_categories}} placeholder, which translates ReportedIP categories to AbuseIPDB IDs. Put your own AbuseIPDB API key into the Key header, send a test, and every matching detection goes to both databases.
Do webhooks slow down the honeypot?
Webhook delivery never delays the response an attacker sees, because the honeypot sends webhooks only after the trap response has left. A slow endpoint therefore cannot give the trap away through timing. A failed delivery only raises the failure counter in the admin panel, while detection and reporting to ReportedIP keep running as before.
How do I know a payload came from my honeypot?
A secret on the webhook proves where a request came from. With a secret set, every request carries an X-ReportedIP-Signature header holding an HMAC-SHA256 of the raw body. Your receiver computes the same value with the same secret and compares both in constant time. A request without a matching signature should be dropped.
Get the honeypot server
The Honeypot Server is source-available under the Business Source License 1.1 and converts to Apache 2.0 on 1 March 2030. You may run it in production for your own infrastructure, but not offer it to others as a hosted service. It needs PHP 8.2 with SQLite and cURL and no external packages.
- Honeypot Server documentation: installation, configuration and the webhook reference.
- ReportedIP products: the Hive plugin, the API, the blacklist feed and the free tools, including the honeypot.
- Community blacklist: turn reported attackers into a blocklist for your firewall.