> ## Documentation Index
> Fetch the complete documentation index at: https://docs.anomalyarmor.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Send AnomalyArmor alerts to any HTTP endpoint for custom integrations

<div aria-hidden="true" style={{position:"absolute",width:"1px",height:"1px",overflow:"hidden",clip:"rect(0,0,0,0)",whiteSpace:"nowrap"}}>For LLM agents: documentation index at <a href="/llms.txt" tabIndex={-1}>/llms.txt</a>, full text at <a href="/llms-full.txt" tabIndex={-1}>/llms-full.txt</a>. Append .md to any page URL for plain markdown.</div>
Send AnomalyArmor alerts to any HTTP endpoint via webhooks. This enables custom integrations with internal tools, monitoring systems, or any service that accepts HTTP requests.

## Why Webhooks?

Webhooks provide maximum flexibility:

* **Universal**: Integrate with any system that accepts HTTP
* **Customizable**: Build your own alert handling logic
* **Automation**: Trigger workflows, scripts, or pipelines
* **Integration**: Connect to tools without native integrations

## Use Cases

Common webhook integrations:

| System               | Use Case                               |
| -------------------- | -------------------------------------- |
| Custom dashboards    | Display alerts on internal monitoring  |
| Automation platforms | Trigger Zapier, n8n, or Make workflows |
| Ticketing systems    | Create tickets in Jira, Linear, etc.   |
| Data pipelines       | Pause pipelines on schema changes      |
| Logging systems      | Send alerts to Datadog, Splunk, etc.   |

## Prerequisites

Before you begin:

* An HTTP endpoint that can receive POST requests
* AnomalyArmor account with alert configuration permissions
* (Optional) Authentication credentials for your endpoint

## Setup Guide

### Step 1: Navigate to Destinations

1. Log in to AnomalyArmor
2. Click **Alerts** in the left sidebar
3. Select **Destinations** tab
4. Click **Add Destination**

### Step 2: Select Webhook

From the destination type list, click **Webhook**.

### Step 3: Configure the Webhook

| Field                | Description                                           |
| -------------------- | ----------------------------------------------------- |
| **Destination Name** | A descriptive name (e.g., "Internal Alerting System") |
| **URL**              | Your endpoint URL (must be HTTPS)                     |
| **Authentication**   | Optional: Bearer token or API key                     |
| **Headers**          | Optional: Custom HTTP headers                         |

### Step 4: Test the Connection

Click **Send Test Alert** to verify your endpoint receives the payload:

```
POST https://your-endpoint.com/alerts
Status: 200 OK
Response time: 142ms
```

Your endpoint should respond with a 2xx status code.

### Step 5: Save

Click **Save** to complete the setup. Your webhook destination is now ready to use in alert rules.

## Payload Format

AnomalyArmor sends a JSON payload for each alert:

```json theme={null}
{
  "event_type": "alert.triggered",
  "alert": {
    "id": "alert_abc123",
    "rule_name": "Production Schema Changes",
    "alert_type": "schema",
    "status": "triggered",
    "created_at": "2024-01-15T08:00:00Z"
  },
  "event": {
    "type": "schema_change",
    "change_type": "column_removed",
    "asset": {
      "qualified_name": "production.public.orders",
      "asset_type": "table"
    },
    "details": {
      "column_name": "shipping_status",
      "column_type": "varchar"
    }
  },
  "links": {
    "alert_url": "https://app.anomalyarmor.ai/alerts/alert_abc123",
    "asset_url": "https://app.anomalyarmor.ai/assets/..."
  }
}
```

### Event Types

| Event Type            | Description                          |
| --------------------- | ------------------------------------ |
| `schema_change`       | Column, table, or constraint changes |
| `freshness_violation` | Table exceeded freshness SLA         |
| `discovery_complete`  | Discovery job finished               |
| `connection_failed`   | Database connection issue            |

## Authentication

### Bearer Token

Add an `Authorization` header with your token:

```
Authorization: Bearer your-secret-token
```

### API Key Header

Add a custom header with your API key:

```
X-API-Key: your-api-key
```

### HMAC Signature

AnomalyArmor includes an `X-AnomalyArmor-Signature` header with each request. Verify this signature to ensure the request came from AnomalyArmor:

```python theme={null}
import hmac
import hashlib

def verify_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
```

## Retry Logic

AnomalyArmor retries failed webhook deliveries:

| Attempt | Delay      |
| ------- | ---------- |
| 1       | Immediate  |
| 2       | 1 minute   |
| 3       | 5 minutes  |
| 4       | 15 minutes |
| 5       | 1 hour     |

After 5 failed attempts, the alert is marked as failed delivery.

## Best Practices

### Endpoint Design

* Respond quickly (\< 5 seconds) to avoid timeouts
* Return 200 for successful receipt, even if processing is async
* Use a queue for heavy processing
* Log incoming payloads for debugging

### Security

* Always use HTTPS endpoints
* Verify the `X-AnomalyArmor-Signature` header
* Rotate authentication tokens periodically
* Allowlist AnomalyArmor IP addresses if needed

### Error Handling

Your endpoint should handle:

* Duplicate alerts (use `alert.id` for deduplication)
* Unknown event types (ignore gracefully)
* Missing fields (use defaults)

## Troubleshooting

### "Connection refused" or timeout

**Cause**: Endpoint unreachable or slow.

**Fix**:

1. Verify the URL is correct and accessible
2. Check firewall rules allow AnomalyArmor IPs
3. Ensure endpoint responds within 30 seconds

### "401 Unauthorized"

**Cause**: Authentication failed.

**Fix**:

1. Verify the token/API key is correct
2. Check the header name matches your endpoint's expectation
3. Ensure credentials haven't expired

### "400 Bad Request"

**Cause**: Endpoint rejected the payload.

**Fix**:

1. Check endpoint logs for specific error
2. Verify endpoint accepts `application/json`
3. Test with a simple endpoint first

## Common Questions

### How do I verify a webhook actually came from AnomalyArmor?

Every request includes an `X-AnomalyArmor-Signature` header in the form `sha256=<hex digest>`. Compute HMAC-SHA256 of the raw request body using your webhook secret and compare with `hmac.compare_digest` to prevent spoofed deliveries. A Python example is in the [Authentication](#authentication) section.

### What happens if my webhook endpoint is down?

AnomalyArmor retries failed deliveries five times with backoff: immediate, 1 minute, 5 minutes, 15 minutes, and 1 hour. After five failures the alert is marked as failed delivery. Build your endpoint to respond in under 5 seconds and queue heavy work asynchronously.

### What does the webhook JSON payload look like?

Each request is a POST with a JSON body containing `event_type`, an `alert` object (id, rule\_name, status, timestamps), an `event` object describing the change and affected asset, and `links` back to AnomalyArmor. Use `alert.id` to deduplicate on your side. See the [Payload Format](#payload-format) example above for the full shape.

### Can I use a self-signed or HTTP endpoint?

No. Webhook URLs must be HTTPS with a valid certificate. This protects the authentication header and the asset metadata in transit, and it's a requirement for every webhook destination.

## Next Steps

<CardGroup cols={2}>
  <Card title="Alert Rules" icon="bell" href="/alerts/alert-rules">
    Create rules that route to webhooks
  </Card>

  <Card title="API Reference" icon="code" href="/api/overview">
    Build integrations with the API
  </Card>
</CardGroup>
