Webhooks
Webhooks enable real-time notifications when events occur in Tamandua. You can configure outbound webhooks to push alerts to external systems, and inbound webhooks to receive data from SIEM/SOAR platforms.
Outbound Webhooks
Webhook Events
Tamandua can send webhooks for the following event types:
| Event | Description |
|---|---|
alert.created | New alert generated |
alert.updated | Alert status changed |
alert.resolved | Alert marked as resolved |
alert.assigned | Alert assigned to user |
agent.connected | Agent came online |
agent.disconnected | Agent went offline |
agent.isolated | Agent network isolated |
response.executed | Response action completed |
detection.new_threat | New threat type detected |
integration.error | Integration failure |
Configure Webhooks via API
Create Webhook Integration
Endpoint:POST /api/v1/integrations
curl -X POST "https://api.tamandua.io/api/v1/integrations" \
-H "Authorization: Bearer tam_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"type": "webhook",
"name": "Security Team Alerts",
"description": "Send critical alerts to security team webhook",
"enabled": true,
"config": {
"url": "https://your-server.com/webhook/tamandua",
"secret": "your-webhook-secret-here",
"events": ["alert.created", "alert.resolved"],
"severity_filter": ["critical", "high"],
"headers": {
"X-Custom-Header": "custom-value"
},
"retry_count": 3,
"timeout_seconds": 30
}
}'
Response:
{
"data": {
"id": "int-550e8400-e29b-41d4-a716-446655440000",
"type": "webhook",
"name": "Security Team Alerts",
"description": "Send critical alerts to security team webhook",
"enabled": true,
"config": {
"url": "https://your-server.com/webhook/tamandua",
"secret": "**********************",
"events": ["alert.created", "alert.resolved"],
"severity_filter": ["critical", "high"]
},
"created_at": "2024-01-15T10:00:00Z"
}
}
List Webhooks
Endpoint:GET /api/v1/integrations?type=webhook
curl -X GET "https://api.tamandua.io/api/v1/integrations?type=webhook" \
-H "Authorization: Bearer tam_live_xxxxx"
Update Webhook
Endpoint:PUT /api/v1/integrations/:id
curl -X PUT "https://api.tamandua.io/api/v1/integrations/int-550e8400" \
-H "Authorization: Bearer tam_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"enabled": false,
"config": {
"severity_filter": ["critical"]
}
}'
Delete Webhook
Endpoint:DELETE /api/v1/integrations/:id
curl -X DELETE "https://api.tamandua.io/api/v1/integrations/int-550e8400" \
-H "Authorization: Bearer tam_live_xxxxx"
Test Webhook
Endpoint:POST /api/v1/integrations/:id/test
curl -X POST "https://api.tamandua.io/api/v1/integrations/int-550e8400/test" \
-H "Authorization: Bearer tam_live_xxxxx"
Response:
{
"success": true,
"message": "Connection successful",
"details": {
"status_code": 200,
"response_time_ms": 150
}
}
Webhook Payload Format
Alert Created Event
{
"event": "alert.created",
"timestamp": "2024-01-15T14:30:00Z",
"webhook_id": "int-550e8400",
"data": {
"alert": {
"id": "alert-001",
"title": "Ransomware behavior detected",
"description": "Mass file encryption activity detected",
"severity": "critical",
"status": "open",
"threat_score": 95,
"agent_id": "agent-001",
"agent_hostname": "WORKSTATION-01",
"mitre_tactics": ["impact"],
"mitre_techniques": ["T1486"],
"evidence": {
"files_encrypted": 150,
"process_name": "unknown.exe"
},
"created_at": "2024-01-15T14:30:00Z"
}
}
}
Alert Updated Event
{
"event": "alert.updated",
"timestamp": "2024-01-15T15:00:00Z",
"webhook_id": "int-550e8400",
"data": {
"alert": {
"id": "alert-001",
"title": "Ransomware behavior detected",
"severity": "critical",
"status": "investigating",
"previous_status": "open",
"assigned_to": {
"id": "user-123",
"name": "John Doe",
"email": "john@example.com"
},
"updated_at": "2024-01-15T15:00:00Z"
},
"changes": {
"status": ["open", "investigating"],
"assigned_to_id": [null, "user-123"]
}
}
}
Agent Disconnected Event
{
"event": "agent.disconnected",
"timestamp": "2024-01-15T14:35:00Z",
"webhook_id": "int-550e8400",
"data": {
"agent": {
"id": "agent-001",
"hostname": "WORKSTATION-01",
"os_type": "windows",
"last_seen": "2024-01-15T14:34:55Z",
"disconnect_reason": "timeout"
}
}
}
Response Executed Event
{
"event": "response.executed",
"timestamp": "2024-01-15T14:31:00Z",
"webhook_id": "int-550e8400",
"data": {
"response": {
"id": "resp-001",
"type": "rapid_response",
"agent_id": "agent-001",
"agent_hostname": "WORKSTATION-01",
"alert_id": "alert-001",
"actions": [
{"action": "kill_process", "pid": 1234, "result": "success"},
{"action": "quarantine_file", "path": "C:\\malware.exe", "result": "success"},
{"action": "isolate_network", "result": "success"}
],
"automated": true,
"executed_by": null,
"executed_at": "2024-01-15T14:31:00Z",
"duration_ms": 250
}
}
}
Signature Verification
All outbound webhooks include an HMAC signature for verification. The signature is computed using SHA-256 and included in the X-Tamandua-Signature header.
Signature Format
X-Tamandua-Signature: sha256=<hex-encoded-signature>
X-Tamandua-Timestamp: 1705329000
Verification Example (Python)
import hmac
import hashlib
import time
def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
# Check timestamp is within 5 minutes
if abs(time.time() - int(timestamp)) > 300:
return False
# Compute expected signature
signed_payload = f"{timestamp}.{payload.decode()}"
expected = hmac.new(
secret.encode(),
signed_payload.encode(),
hashlib.sha256
).hexdigest()
# Compare signatures (constant-time)
received = signature.replace("sha256=", "")
return hmac.compare_digest(expected, received)
# Usage
is_valid = verify_webhook(
payload=request.body,
signature=request.headers["X-Tamandua-Signature"],
timestamp=request.headers["X-Tamandua-Timestamp"],
secret="your-webhook-secret"
)
Verification Example (Node.js)
const crypto = require('crypto');
function verifyWebhook(payload, signature, timestamp, secret) {
// Check timestamp is within 5 minutes
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return false;
}
// Compute expected signature
const signedPayload = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Compare signatures (constant-time)
const received = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
Retry Policy
Failed webhook deliveries are retried with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
After 5 failed attempts, the webhook is marked as failed and the integration is flagged for review.
Response Requirements
Your webhook endpoint should:
- Return HTTP 2xx status code for success
- Respond within 30 seconds (configurable)
- Handle duplicate deliveries idempotently
Inbound Webhooks
Receive webhooks from external SIEM/SOAR platforms.
Supported Sources
| Source | Description |
|---|---|
splunk | Splunk SOAR/Enterprise Security |
sentinel | Microsoft Sentinel |
qradar | IBM QRadar |
pagerduty | PagerDuty incidents |
slack | Slack interactive messages |
generic | Generic webhook format |
Inbound Webhook Endpoint
Endpoint:POST /api/v1/integrations/webhook/:source
Splunk Webhook Example
curl -X POST "https://api.tamandua.io/api/v1/integrations/webhook/splunk" \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: sha256=abc123..." \
-d '{
"alert_name": "Suspicious Process",
"severity": "high",
"source_ip": "10.0.0.50",
"dest_ip": "192.168.1.100",
"raw_event": "..."
}'
PagerDuty Webhook Example
curl -X POST "https://api.tamandua.io/api/v1/integrations/webhook/pagerduty" \
-H "Content-Type: application/json" \
-H "X-PagerDuty-Signature: v1=abc123..." \
-d '{
"event": {
"event_type": "incident.triggered",
"incident": {
"id": "P123ABC",
"title": "Critical Alert",
"urgency": "high"
}
}
}'
Inbound Signature Verification
Inbound webhooks are verified using the configured secret for each source. The secret is stored server-side and never exposed in requests.
Supported Signature Headers:X-Hub-Signature-256(GitHub style)X-Webhook-SignatureX-SignatureX-Tines-SignatureX-Slack-Signature
Configure Inbound Webhook Secrets
Set secrets via environment variables or application config:
# Environment variables
WEBHOOK_SECRET_SPLUNK=your-splunk-secret
WEBHOOK_SECRET_PAGERDUTY=your-pagerduty-secret
WEBHOOK_SECRET_GENERIC=your-generic-secret
Webhook History
View inbound webhook history:
Endpoint:GET /api/v1/integrations/webhook/history
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
source | string | Filter by source |
status | string | Filter by status: success, error |
limit | integer | Max results (default: 100) |
offset | integer | Skip results |
{
"data": [
{
"id": "wh-001",
"source": "splunk",
"status": "success",
"payload_size": 1520,
"duration_ms": 45,
"error": null,
"timestamp": "2024-01-15T14:30:00Z"
},
{
"id": "wh-002",
"source": "pagerduty",
"status": "error",
"payload_size": 890,
"duration_ms": 150,
"error": "Invalid signature",
"timestamp": "2024-01-15T14:25:00Z"
}
],
"meta": {
"total": 1520,
"limit": 100,
"offset": 0
}
}
Routing Rules
Configure rules to route alerts to specific integrations based on conditions.
List Routing Rules
Endpoint:GET /api/v1/integrations/rules
Create Routing Rule
Endpoint:POST /api/v1/integrations/rules
curl -X POST "https://api.tamandua.io/api/v1/integrations/rules" \
-H "Authorization: Bearer tam_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"name": "Critical to PagerDuty",
"description": "Route critical alerts to PagerDuty",
"conditions": [
{"field": "severity", "operator": "eq", "value": "critical"},
{"field": "status", "operator": "eq", "value": "open"}
],
"destinations": ["pagerduty-integration-id"],
"enabled": true,
"priority": 10
}'
Response:
{
"data": {
"id": "rule-001",
"name": "Critical to PagerDuty",
"conditions": [
{"field": "severity", "operator": "eq", "value": "critical"},
{"field": "status", "operator": "eq", "value": "open"}
],
"destinations": ["pagerduty-integration-id"],
"enabled": true,
"priority": 10
}
}
Condition Operators
| Operator | Description | Example |
|---|---|---|
eq | Equals | {"field": "severity", "operator": "eq", "value": "critical"} |
ne | Not equals | {"field": "status", "operator": "ne", "value": "resolved"} |
in | In list | {"field": "severity", "operator": "in", "value": ["critical", "high"]} |
contains | Contains substring | {"field": "title", "operator": "contains", "value": "ransomware"} |
matches | Regex match | {"field": "hostname", "operator": "matches", "value": "^DC-.*"} |
gt, gte, lt, lte | Numeric comparison | {"field": "threat_score", "operator": "gte", "value": 80} |
Test Routing
Test which rules would match an alert:
Endpoint:POST /api/v1/integrations/rules/test
curl -X POST "https://api.tamandua.io/api/v1/integrations/rules/test" \
-H "Authorization: Bearer tam_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{
"alert": {
"severity": "critical",
"status": "open",
"title": "Ransomware detected",
"threat_score": 95
}
}'
Response:
{
"data": {
"matched_rules": [
{
"id": "rule-001",
"name": "Critical to PagerDuty",
"destinations": ["pagerduty-integration-id"]
}
],
"destinations": ["pagerduty-integration-id"]
}
}
Integration Statistics
Endpoint:GET /api/v1/integrations/stats
{
"data": {
"alerts_routed": 1520,
"rules_matched": 1450,
"destinations_triggered": 2100,
"errors": 12,
"by_destination": {
"webhook-001": {"success": 500, "failed": 2},
"pagerduty-001": {"success": 300, "failed": 5}
},
"by_rule": {
"rule-001": 800,
"rule-002": 650
},
"last_activity": "2024-01-15T14:30:00Z"
}
}
Integration Logs
View detailed logs for integration activity:
Endpoint:GET /api/v1/integrations/logs
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
integration_name | string | Filter by integration |
status | string | Filter by status |
action | string | Filter by action |
from | string | Start date (ISO 8601) |
to | string | End date (ISO 8601) |
limit | integer | Max results |
offset | integer | Skip results |
summary | boolean | Return aggregated summary |
{
"data": [
{
"id": "log-001",
"integration_name": "pagerduty",
"action": "create_incident",
"status": "success",
"request_body": {...},
"response_body": {...},
"error_message": null,
"duration_ms": 250,
"inserted_at": "2024-01-15T14:30:00Z"
}
],
"meta": {
"total": 1520,
"limit": 100,
"offset": 0
}
}
Pre-built Integrations
Tamandua includes pre-built integrations for common platforms:
Slack
{
"type": "slack",
"config": {
"webhook_url": "https://hooks.slack.com/services/...",
"channel": "#security-alerts",
"username": "Tamandua",
"icon_emoji": ":shield:"
}
}
Microsoft Teams
{
"type": "teams",
"config": {
"webhook_url": "https://outlook.office.com/webhook/..."
}
}
PagerDuty
{
"type": "pagerduty",
"config": {
"routing_key": "your-pagerduty-routing-key",
"severity_mapping": {
"critical": "critical",
"high": "error",
"medium": "warning",
"low": "info"
}
}
}
Splunk HEC
{
"type": "splunk",
"config": {
"hec_url": "https://splunk.example.com:8088",
"hec_token": "your-hec-token",
"index": "security",
"source": "tamandua",
"sourcetype": "_json"
}
}
ServiceNow
{
"type": "servicenow",
"config": {
"instance_url": "https://your-instance.service-now.com",
"username": "api_user",
"password": "api_password",
"table": "incident"
}
}