Skip to content

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.

curl -s https://stentor.app/api/v1/cockpit/webhooks \
  -H "Authorization: Bearer $TOKEN"

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
curl -s -X PUT https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["beacon_new", "credential_added"]
  }'
curl -s -X PUT https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": false
  }'

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.

curl -s -X POST https://stentor.app/api/v1/cockpit/webhooks/$WEBHOOK_ID/test \
  -H "Authorization: Bearer $TOKEN"

Response (200 OK):

{
  "message": "test notification sent"
}

Error Response (502 Bad Gateway):

{
  "error": "webhook returned HTTP 404"
}

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:

{
  "filters": {
    "hostname": "DC01"
  }
}

This webhook only fires when the event payload contains hostname matching "DC01" (case-insensitive).

Only fire for NTLM credential harvests:

{
  "filters": {
    "credential_type": "ntlm"
  }
}

This webhook only fires for credential_added events where the credential type is "ntlm".

Only fire for a specific user on a specific host:

{
  "filters": {
    "hostname": "WS01",
    "username": "CORP\\admin"
  }
}

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:

{
  "message": "test notification sent"
}

Failure response (e.g., invalid URL or provider rejected the payload):

{
  "error": "webhook returned HTTP 404"
}

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

  1. Navigate to Preferences > Webhook Settings
  2. Click Add Webhook to open the create dialog
  3. Select a provider (Slack, Discord, or Teams)
  4. Paste the webhook URL from your provider
  5. Select which events should trigger notifications
  6. Optionally add filter criteria to narrow event scope
  7. Click Save to create the endpoint
  8. Click the Test button to verify the configuration
  9. 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