Webhook Notifications¶
Webhook notifications deliver real-time alerts to Slack, Discord, or Microsoft Teams channels when significant C2 events occur. Instead of polling the dashboard, operators receive instant push notifications for new beacons, lost beacons, completed tasks, and harvested credentials -- all formatted natively for each provider.
Supported Providers¶
Stentor supports three webhook providers. Each provider receives payloads formatted in its native messaging format for rich, interactive notifications.
| Provider | Webhook URL Format | Payload Format |
|---|---|---|
slack | https://hooks.slack.com/services/T.../B.../xxx | Block Kit (header + section blocks with mrkdwn) |
discord | https://discord.com/api/webhooks/123456/abcdef | Embeds with color-coded borders |
teams | https://outlook.office.com/webhook/... (Incoming Webhook connector) | Adaptive Cards v1.4 |
Obtaining Webhook URLs
- Slack: Create an Incoming Webhook in your Slack workspace settings
- Discord: Open Channel Settings > Integrations > Webhooks > New Webhook > Copy Webhook URL
- Teams: Add an Incoming Webhook connector to your Teams channel and copy the generated URL
Event Types¶
Four event types can trigger webhook notifications. Each event has an associated color used for Discord embed borders and a specific set of payload fields.
| Event | Display Title | Color | Description |
|---|---|---|---|
beacon_new | New Beacon | Green (#22C55E) | Fires when a new implant registers with the C2 server |
beacon_dead | Beacon Lost | Red (#EF4444) | Fires when a beacon misses check-ins and is marked dead |
task_complete | Task Complete | Blue (#3B82F6) | Fires when a task execution completes on a beacon |
credential_added | Credential Harvested | Amber (#F59E0B) | Fires when a credential is harvested from a target |
Payload Fields¶
Each event type exposes different payload fields in the notification message:
| Field | Description |
|---|---|
hostname | Target machine hostname |
username | Current user context |
ip | Beacon IP address |
os | Operating system (e.g., "Windows 10 Pro") |
pid | Beacon process ID |
Example message: Host: WS01 | User: CORP\jsmith | IP: 10.10.10.21 | OS: Windows 10 Pro | PID: 4832
| Field | Description |
|---|---|
hostname | Target machine hostname |
username | Current user context |
ip | Beacon IP address |
last_seen | Timestamp of last check-in |
Example message: Host: WS01 | User: CORP\jsmith | IP: 10.10.10.21 | Last Seen: 2026-02-21T10:00:00Z
| Field | Description |
|---|---|
beacon | Beacon identifier |
task_type | Type of task that completed |
output | Task output (truncated to 200 characters) |
Example message: Beacon: a1b2c3d4 | Task: exec.shell | Output: USER INFORMATION...
| Field | Description |
|---|---|
credential_type | Credential type (e.g., ntlm, kerberos, plaintext) |
username | Credential username |
source | Source of the credential (e.g., lsass, sam, dcsync) |
Example message: Type: ntlm | Username: CORP\admin | Source: lsass
API Reference¶
All webhook endpoints are under the cockpit route group and require JWT authentication.
Base path: /api/v1/cockpit/webhooks
| Method | Endpoint | Description |
|---|---|---|
GET | /api/v1/cockpit/webhooks | List all webhook endpoints |
POST | /api/v1/cockpit/webhooks | Create a new webhook endpoint |
PUT | /api/v1/cockpit/webhooks/:id | Update a webhook endpoint |
DELETE | /api/v1/cockpit/webhooks/:id | Delete a webhook endpoint |
POST | /api/v1/cockpit/webhooks/:id/test | Send a test notification |
GET | /api/v1/cockpit/webhooks/:id/logs | List delivery logs (last 50) |
Create Webhook Endpoint¶
POST /api/v1/cockpit/webhooks
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the webhook endpoint |
provider | string | Yes | Provider type: slack, discord, or teams |
url | string | Yes | Webhook URL for the provider |
events | string[] | Yes | Array of event types to subscribe to |
filters | object | No | JSON filter object for event matching (defaults to {}) |
curl -s -X POST https://stentor.app/api/v1/cockpit/webhooks \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Slack Alerts",
"provider": "slack",
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
"events": ["beacon_new", "beacon_dead", "credential_added"],
"filters": {}
}'
Response (201 Created):
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Slack Alerts",
"provider": "slack",
"url": "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX",
"events": ["beacon_new", "beacon_dead", "credential_added"],
"filters": {},
"enabled": true,
"created_at": "2026-02-21T10:00:00Z",
"updated_at": "2026-02-21T10:00:00Z"
}
List Webhook Endpoints¶
GET /api/v1/cockpit/webhooks
Returns all configured webhook endpoints.
Update Webhook Endpoint¶
PUT /api/v1/cockpit/webhooks/:id
Supports partial updates -- only provided fields are modified. All fields are optional.
Request Body:
| Field | Type | Required | Description |
|---|---|---|---|
name | string | No | Updated display name |
provider | string | No | Updated provider (slack, discord, teams) |
url | string | No | Updated webhook URL |
events | string[] | No | Updated event subscriptions |
filters | object | No | Updated filter object |
enabled | boolean | No | Enable or disable the endpoint |
Delete Webhook Endpoint¶
DELETE /api/v1/cockpit/webhooks/:id
Permanently removes a webhook endpoint and all associated delivery logs.
curl -s -X DELETE https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID \
-H "Authorization: Bearer $TOKEN"
Response: 204 No Content
Send Test Notification¶
POST /api/v1/cockpit/webhooks/:id/test
Sends a test notification to the webhook endpoint to verify the configuration is working. See the Test Send section for details on the test payload.
List Delivery Logs¶
GET /api/v1/cockpit/webhooks/:id/logs
Returns the last 50 delivery attempts for a webhook endpoint, ordered by most recent first. See the Delivery Logs section for field descriptions.
curl -s https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID/logs \
-H "Authorization: Bearer $TOKEN"
Filtering¶
Filters allow you to narrow which events trigger a webhook notification. The filter object is a JSON key-value map where keys match payload field names and values are compared against the event payload.
How Filtering Works¶
- Empty filters (
{}) -- All events matching the subscribed event types pass through (default behavior) - String comparison -- Filter values are compared case-insensitively using
strings.EqualFold - Missing fields -- If a filter key does not exist in the event payload, that filter criterion is skipped (does not block delivery)
- Multiple filters -- All filter criteria must match for the event to pass (logical AND)
Filter Examples¶
Only fire for events from a specific host:
This webhook only fires when the event payload contains hostname matching "DC01" (case-insensitive).
Only fire for NTLM credential harvests:
This webhook only fires for credential_added events where the credential type is "ntlm".
Only fire for a specific user on a specific host:
Both conditions must match (AND logic) for the webhook to fire.
Filter Scope
Filters apply to the event payload fields documented in the Event Types section. For example, beacon_new events expose hostname, username, ip, os, and pid -- you can filter on any of these fields.
Provider Payload Formats¶
Each provider receives notifications in its native messaging format for optimal rendering.
Slack¶
Slack webhooks receive Block Kit payloads with a header block showing the event title and a section block with mrkdwn-formatted event details.
{
"blocks": [
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Stentor: New Beacon"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Host: WS01 | User: CORP\\jsmith | IP: 10.10.10.21 | OS: Windows 10 Pro | PID: 4832"
}
}
]
}
Discord¶
Discord webhooks receive Embed payloads with color-coded borders matching the event type and an ISO 8601 timestamp.
{
"embeds": [
{
"title": "Stentor: New Beacon",
"description": "Host: WS01 | User: CORP\\jsmith | IP: 10.10.10.21 | OS: Windows 10 Pro | PID: 4832",
"color": 2278494,
"timestamp": "2026-02-21T10:00:00Z"
}
]
}
The color field is an integer representation of the event color (e.g., 0x22C55E = 2278494 for green).
Microsoft Teams¶
Teams webhooks receive Adaptive Card v1.4 payloads wrapped in a message attachment. The card contains a bold title TextBlock and a wrapping description TextBlock.
{
"type": "message",
"attachments": [
{
"contentType": "application/vnd.microsoft.card.adaptive",
"content": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.4",
"body": [
{
"type": "TextBlock",
"text": "Stentor: New Beacon",
"weight": "bolder",
"size": "medium"
},
{
"type": "TextBlock",
"text": "Host: WS01 | User: CORP\\jsmith | IP: 10.10.10.21 | OS: Windows 10 Pro | PID: 4832",
"wrap": true
}
]
}
}
]
}
Test Send¶
Before relying on a webhook for live alerts, use the test-send endpoint to verify your configuration. The test notification uses a fixed payload that exercises the full delivery pipeline without requiring real C2 events.
Test Payload¶
The test-send uses the following payload fields:
| Field | Value |
|---|---|
hostname | TEST-HOST |
username | test_user |
ip | 10.0.0.1 |
os | Windows 10 Pro |
pid | 1234 |
The notification appears in your channel with the title "Stentor: Test Notification" and a purple accent color (Discord) or standard formatting (Slack/Teams).
Sending a Test¶
curl -s -X POST https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID/test \
-H "Authorization: Bearer $TOKEN"
Success response:
Failure response (e.g., invalid URL or provider rejected the payload):
Verify Before Deploying
Always send a test notification after creating or updating a webhook endpoint. This confirms the URL is correct, the provider accepts the payload format, and your network allows outbound HTTPS connections to the provider's servers.
Delivery Logs¶
Every webhook delivery attempt is recorded in a delivery log. Logs are stored per-endpoint and can be queried to troubleshoot delivery failures, verify successful notifications, or audit webhook activity.
Delivery Log Fields¶
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique log entry identifier |
endpoint_id | string (UUID) | Parent webhook endpoint |
event_type | string | Event type that triggered the delivery (beacon_new, beacon_dead, task_complete, credential_added, or test) |
status_code | integer or null | HTTP status code from the provider (null if connection failed) |
success | boolean | Whether the delivery was successful (HTTP 2xx) |
error_message | string or null | Error description if delivery failed |
delivered_at | string (ISO 8601) | Timestamp of the delivery attempt |
Querying Delivery Logs¶
The API returns the last 50 delivery log entries for a given endpoint.
curl -s https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID/logs \
-H "Authorization: Bearer $TOKEN"
Response (200 OK):
[
{
"id": "aaa11111-bbbb-cccc-dddd-eeeeeeeeeeee",
"endpoint_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "beacon_new",
"status_code": 200,
"success": true,
"error_message": null,
"delivered_at": "2026-02-21T10:05:00Z"
},
{
"id": "bbb22222-cccc-dddd-eeee-ffffffffffff",
"endpoint_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"event_type": "credential_added",
"status_code": null,
"success": false,
"error_message": "Post \"https://hooks.slack.com/services/...\": dial tcp: lookup hooks.slack.com: no such host",
"delivered_at": "2026-02-21T09:55:00Z"
}
]
Log Retention
The API returns the most recent 50 delivery log entries per endpoint. Older entries remain in the database but are not returned by the API.
UI Configuration¶
The webhook configuration interface is integrated into the Preferences page under the Webhook Settings card.
Features¶
- Create/Edit dialog -- Configure webhook name, provider, URL, events, and filters through a form dialog
- Enable/Disable toggle -- Temporarily disable a webhook endpoint without deleting it
- Inline test-send -- Click the test button to send a test notification directly from the endpoint list
- Delivery log viewer -- Expand any endpoint row to view recent delivery logs with status indicators (green check for success, red X for failure)
- Event badges -- Each endpoint displays its subscribed events as colored badges
Workflow¶
- Navigate to Preferences > Webhook Settings
- Click Add Webhook to open the create dialog
- Select a provider (Slack, Discord, or Teams)
- Paste the webhook URL from your provider
- Select which events should trigger notifications
- Optionally add filter criteria to narrow event scope
- Click Save to create the endpoint
- Click the Test button to verify the configuration
- Check your channel for the test notification
Troubleshooting¶
| Issue | Cause | Fix |
|---|---|---|
Test-send returns 502 Bad Gateway | Webhook URL is incorrect or the provider rejected the request | Verify the URL is a valid incoming webhook URL for the selected provider. Check that the webhook has not been revoked or deleted in the provider's settings. |
status_code: null in delivery logs | Network connection failed before reaching the provider | Check outbound HTTPS connectivity from the Stentor server. Ensure firewall rules allow connections to hooks.slack.com, discord.com, or outlook.office.com. |
| Notifications stop arriving | Webhook endpoint was disabled or the provider rotated/revoked the URL | Check the endpoint enabled status via the API or UI. Re-generate the webhook URL in the provider's settings if it was rotated. |
"invalid provider" error on create | Provider field is not one of the accepted values | Use exactly slack, discord, or teams (lowercase). |
"invalid event" error on create | One or more events in the array are not recognized | Use only beacon_new, beacon_dead, task_complete, or credential_added. |
| Webhook fires for unwanted events | Filters are too broad or empty | Add filter criteria to narrow the scope. For example, {"hostname": "DC01"} restricts notifications to events from that host. |
| Rate limiting from provider | Too many notifications in a short period | Reduce the number of subscribed events or add filters to limit notification volume. Slack rate-limits to approximately 1 message per second per webhook URL. |
| Teams card not rendering | Adaptive Card schema version mismatch | Stentor sends Adaptive Card v1.4 payloads. Ensure your Teams channel supports this version (most modern Teams clients do). |
Cross-References¶
- REST API Reference -- Webhook endpoints are listed under the Cockpit section
- Playbooks -- Automate multi-step beacon workflows that can trigger webhook events
- Beacon Grouping -- Group beacons for organized monitoring; filter webhook events by hostname to match group patterns