Configure real-time HTTP event callbacks, verify cryptographic HMAC-SHA256 signatures, test live payloads, and inspect delivery telemetry.
Quick Reference
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/v1/webhooks/endpoints | GET | webhooks:read | List all registered webhook endpoints for the account. |
/v1/webhooks/endpoints | POST | webhooks:write | Register a new HTTPS webhook destination and generate a signing secret. |
/v1/webhooks/endpoints/:id | GET | webhooks:read | Retrieve configuration and metadata for a specific webhook endpoint. |
/v1/webhooks/endpoints/:id | PATCH | webhooks:write | Update webhook endpoint name, target URL, payload format, or active state. |
/v1/webhooks/endpoints/:id | DELETE | webhooks:write | Permanently remove a webhook endpoint. |
/v1/webhooks/test | POST | webhooks:write | Dispatch an immediate simulated event payload with anti-SSRF validation. |
/v1/webhooks/deliveries | GET | webhooks:read | Query paginated execution logs, response status codes, and latencies. |
Webhook Architecture & Event Flow
When incoming messages match routing rules or trigger automated workflows, AliasFleet streams structured event payloads directly to your HTTPS servers:
sequenceDiagram
autonumber
actor Sender as Inbound Email Sender
participant Engine as AliasFleet Ingestion Engine
participant Rules as Rules Engine
participant Egress as Anti-SSRF Dispatcher
participant Customer as Your Webhook Server (HTTPS)
Sender->>Engine: Inbound Message Envelope
Engine->>Rules: Evaluate Inbound Rules
Rules->>Rules: Action: send_to_webhook (Endpoint ID)
Rules->>Egress: Assemble Payload & Sign HMAC-SHA256
Egress->>Egress: Validate Egress IP (Reject RFC 1918 / Metadata)
Egress->>Customer: POST /webhook (X-AliasFleet-Signature)
Customer-->>Egress: 200 OK
Egress->>Engine: Record Delivery Log (Latency & Status)
Cryptographic Signature Verification
Every outbound webhook delivery includes an X-AliasFleet-Signature header. Always verify this signature before processing events to confirm that requests originated from AliasFleet and that the payload has not been tampered with in transit.
Signature Header Format
The signature header contains a comma-separated key-value string:
X-AliasFleet-Signature: t=1756972800,v1=9f83a21b4c7d0e9a8b7c6d5e4f3a2b1c8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b
t: The UNIX timestamp (in seconds) when the signature was computed.v1: The HMAC-SHA256 hex digest computed over the signed string${t}.${raw_payload}using your endpoint's signing secret (af_whsec_...).
Delivery Headers
| Header | Description |
|---|---|
Content-Type | application/json |
User-Agent | AliasFleet-Webhook-Simulator/1.0 (+https://aliasfleet.com) |
X-AliasFleet-Signature | Cryptographic signature formatted as t=<timestamp>,v1=<signature>. |
X-AliasFleet-Event | Event type identifier (e.g. email.received). |
X-AliasFleet-Delivery | Unique UUID assigned to this delivery execution. |
Verification Implementation Examples
Node.js / TypeScript
import * as crypto from 'crypto';
interface VerifyOptions {
payload: string; // Raw request body as string or Buffer
header: string; // Value of X-AliasFleet-Signature header
secret: string; // Your endpoint secret (af_whsec_...)
toleranceSeconds?: number; // Max allowed clock drift (default: 300s)
}
export function verifyWebhookSignature({
payload,
header,
secret,
toleranceSeconds = 300,
}: VerifyOptions): boolean {
// 1. Parse header components
const parts = Object.fromEntries(
header.split(',').map((part) => part.split('=').map((s) => s.trim()))
);
const timestamp = parseInt(parts.t, 10);
const signature = parts.v1;
if (!timestamp || !signature) {
return false;
}
// 2. Prevent replay attacks: check timestamp tolerance
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - timestamp) > toleranceSeconds) {
return false;
}
// 3. Compute expected HMAC-SHA256 signature
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// 4. Constant-time comparison to prevent timing attacks
const signatureBuffer = Buffer.from(signature, 'hex');
const expectedBuffer = Buffer.from(expectedSignature, 'hex');
if (signatureBuffer.length !== expectedBuffer.length) {
return false;
}
return crypto.timingSafeEqual(signatureBuffer, expectedBuffer);
}
Python 3
import hmac
import hashlib
import time
def verify_webhook_signature(payload: str, header: str, secret: str, tolerance_seconds: int = 300) -> bool:
# 1. Parse header components
parts = dict(item.split("=") for item in header.split(","))
timestamp_str = parts.get("t")
signature = parts.get("v1")
if not timestamp_str or not signature:
return False
timestamp = int(timestamp_str)
# 2. Check replay attack tolerance
if abs(time.time() - timestamp) > tolerance_seconds:
return False
# 3. Compute expected signature
signed_payload = f"{timestamp}.{payload}".encode("utf-8")
expected = hmac.new(secret.encode("utf-8"), signed_payload, hashlib.sha256).hexdigest()
# 4. Constant-time comparison
return hmac.compare_digest(expected, signature)
Go
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"math"
"strconv"
"strings"
"time"
)
func VerifyWebhookSignature(payload []byte, header string, secret string, toleranceSeconds float64) bool {
parts := make(map[string]string)
for _, item := range strings.Split(header, ",") {
kv := strings.SplitN(strings.TrimSpace(item), "=", 2)
if len(kv) == 2 {
parts[kv[0]] = kv[1]
}
}
tStr, hasT := parts["t"]
sigHex, hasSig := parts["v1"]
if !hasT || !hasSig {
return false
}
timestamp, err := strconv.ParseInt(tStr, 10, 64)
if err != nil {
return false
}
// Check clock drift
if math.Abs(float64(time.Now().Unix()-timestamp)) > toleranceSeconds {
return false
}
// Compute expected HMAC
signedData := fmt.Sprintf("%d.%s", timestamp, string(payload))
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(signedData))
expectedSig := mac.Sum(nil)
actualSig, err := hex.DecodeString(sigHex)
if err != nil {
return false
}
return hmac.Equal(expectedSig, actualSig)
}
List Webhook Endpoints
GET /v1/webhooks/endpoints
Retrieves all registered webhook endpoints configured for the authenticated account.
webhooks:readRate Limit: 60 req/minIdempotent: YescURL Example
curl -X GET "https://api.aliasfleet.com/v1/webhooks/endpoints" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Accept: application/json"
Response (200 OK)
{
"endpoints": [
{
"id": "e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"name": "Production Ingestion Pipeline",
"url": "https://api.mycompany.com/v1/emails/webhook",
"payload_format": "parsed_json",
"is_active": true,
"failure_count": 0,
"last_triggered_at": "2026-09-04T12:00:00.000Z",
"created_at": "2026-09-01T08:30:00.000Z",
"updated_at": "2026-09-04T12:00:00.000Z"
}
]
}
Get Webhook Endpoint by ID
GET /v1/webhooks/endpoints/:id
Retrieves detailed configuration for a specific webhook endpoint.
webhooks:readRate Limit: 60 req/minIdempotent: YescURL Example
curl -X GET "https://api.aliasfleet.com/v1/webhooks/endpoints/e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Accept: application/json"
Response (200 OK)
{
"endpoint": {
"id": "e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"user_id": "00000000-0000-0000-0000-000000000001",
"name": "Production Ingestion Pipeline",
"url": "https://api.mycompany.com/v1/emails/webhook",
"secret_key": "af_whsec_9f83a21b4c7d0e9a8b7c6d5e4f3a2b1c8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b",
"payload_format": "parsed_json",
"is_active": true,
"failure_count": 0,
"last_triggered_at": "2026-09-04T12:00:00.000Z",
"created_at": "2026-09-01T08:30:00.000Z",
"updated_at": "2026-09-04T12:00:00.000Z"
}
}
Create Webhook Endpoint
POST /v1/webhooks/endpoints
Registers a new HTTPS webhook destination, generates a cryptographically secure HMAC signing secret (af_whsec_...), and validates destination constraints.
webhooks:writeRate Limit: 30 req/minIdempotent: NoRequest Body Schema
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name | string | Yes | 1–100 chars | Descriptive label for this webhook destination. |
url | string | Yes | Max 1000 chars | Public HTTPS/HTTP URL to receive POST events. |
payload_format | string | Optional | "parsed_json" | "metadata_only" | "raw_mime" (Default: "parsed_json") | Data format transmitted during deliveries. Note: raw_mime requires a Business plan. |
is_active | boolean | Optional | Default: true | Whether this endpoint actively accepts event deliveries. |
cURL Example
curl -X POST "https://api.aliasfleet.com/v1/webhooks/endpoints" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Content-Type: application/json" \
-d '{
"name": "Production Ingestion Pipeline",
"url": "https://api.mycompany.com/v1/emails/webhook",
"payload_format": "parsed_json",
"is_active": true
}'
Response (201 Created)
{
"message": "Webhook endpoint created successfully",
"endpoint": {
"id": "e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"user_id": "00000000-0000-0000-0000-000000000001",
"name": "Production Ingestion Pipeline",
"url": "https://api.mycompany.com/v1/emails/webhook",
"secret_key": "af_whsec_9f83a21b4c7d0e9a8b7c6d5e4f3a2b1c8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b",
"payload_format": "parsed_json",
"is_active": true,
"failure_count": 0,
"last_triggered_at": null,
"created_at": "2026-09-04T15:00:00.000Z",
"updated_at": "2026-09-04T15:00:00.000Z"
}
}
Error Responses
| Status Code | Code | Error Message | Reason |
|---|---|---|---|
400 | INVALID_URL | "URL must use http or https protocol" | Target URL must be a valid HTTP or HTTPS address. |
403 | LIMIT_REACHED | "Webhook endpoint limit reached for your subscription plan. Please upgrade to Pro or Business." | Quota reached for current subscription tier. |
403 | FEATURE_LOCKED | "Raw MIME webhook streaming is only available on the Business plan." | Account tier does not support raw_mime format. |
Update Webhook Endpoint
PATCH /v1/webhooks/endpoints/:id
Modifies an existing webhook endpoint configuration.
webhooks:writeRate Limit: 30 req/minIdempotent: YesRequest Body Schema
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Optional | Updated descriptive label (1–100 chars). |
url | string | Optional | Updated target HTTPS/HTTP destination URL. |
payload_format | string | Optional | "parsed_json" | "metadata_only" | "raw_mime". |
is_active | boolean | Optional | Enable or disable event dispatches. |
cURL Example
curl -X PATCH "https://api.aliasfleet.com/v1/webhooks/endpoints/e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Ingestion Pipeline",
"is_active": true
}'
Response (200 OK)
{
"message": "Webhook endpoint updated successfully",
"endpoint": {
"id": "e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"name": "Updated Ingestion Pipeline",
"url": "https://api.mycompany.com/v1/emails/webhook",
"payload_format": "parsed_json",
"is_active": true,
"failure_count": 0,
"last_triggered_at": "2026-09-04T12:00:00.000Z",
"created_at": "2026-09-01T08:30:00.000Z",
"updated_at": "2026-09-04T15:30:00.000Z"
}
}
Delete Webhook Endpoint
DELETE /v1/webhooks/endpoints/:id
Permanently removes a webhook endpoint. Inbound rules routing to this endpoint will cease webhook dispatches.
webhooks:writeRate Limit: 30 req/minIdempotent: YescURL Example
curl -X DELETE "https://api.aliasfleet.com/v1/webhooks/endpoints/e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD"
Response (200 OK)
{
"success": true,
"message": "Webhook endpoint deleted successfully"
}
Test Webhook Dispatch
POST /v1/webhooks/test
Dispatches an immediate mock event payload (email.received) to verify network connectivity, SSL certificate handshakes, and HMAC signature computation.
Anti-SSRF Protected: The test runner enforces identical security boundaries as production deliveries, rejecting private subnets, cloud metadata endpoints, and non-routable hostnames.
webhooks:writeRate Limit: 30 req/minIdempotent: NoRequest Body Schema
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
url | string | Yes | Valid URL | The target HTTPS endpoint to test. |
secret_key | string | Optional | 16–128 chars | Secret used to sign the test dispatch. If omitted, a temporary secret is generated. |
payload_format | string | Optional | "parsed_json" | "metadata_only" | "raw_mime" | Format of test event payload (Default: "parsed_json"). |
cURL Example
curl -X POST "https://api.aliasfleet.com/v1/webhooks/test" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Content-Type: application/json" \
-d '{
"url": "https://api.mycompany.com/v1/emails/webhook",
"secret_key": "af_whsec_9f83a21b4c7d0e9a8b7c6d5e4f3a2b1c8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b",
"payload_format": "parsed_json"
}'
Response (200 OK)
{
"success": true,
"status_code": 200,
"response_time_ms": 142,
"response_body": "{\"received\": true}",
"signature_header": "t=1756972800,v1=9f83a21b4c7d0e9a8b7c6d5e4f3a2b1c8e7d6c5b4a3f2e1d0c9b8a7f6e5d4c3b"
}
Query Webhook Deliveries
GET /v1/webhooks/deliveries
Retrieves audit logs of past webhook dispatches, including HTTP status codes, execution response latencies, error messages, and payload snippets.
webhooks:readRate Limit: 60 req/minIdempotent: YesQuery Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
endpoint_id | string | Optional | — | Filter delivery records by a specific webhook endpoint ID. |
limit | integer | Optional | 20 | Number of logs to retrieve (1–50). |
offset | integer | Optional | 0 | Number of records to skip for pagination. |
cURL Example
curl -X GET "https://api.aliasfleet.com/v1/webhooks/deliveries?limit=10" \
-H "Authorization: Bearer afp_live_9k3mF7qP2xL8vN5yR1wZ4tC6bJ0sD" \
-H "Accept: application/json"
Response (200 OK)
{
"deliveries": [
{
"id": "d0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"webhook_endpoint_id": "e0a1b2c3-d4e5-f6a7-b8c9-d0e1f2a3b4c5",
"rule_id": "a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
"status_code": 200,
"response_time_ms": 94,
"error_message": null,
"payload_snippet": {
"event": "email.received",
"recipient": "orders.749@afinbox.com",
"subject": "Monthly Subscription Invoice"
},
"created_at": "2026-09-04T15:32:10.000Z"
}
],
"pagination": {
"total": 48,
"limit": 10,
"offset": 0
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
deliveries | array | List of delivery execution records. |
deliveries[].id | string | Unique identifier for the delivery execution log. |
deliveries[].webhook_endpoint_id | string | ID of the target webhook endpoint. |
deliveries[].rule_id | string | null | ID of the routing rule that triggered this dispatch, or null for manual tests. |
deliveries[].status_code | integer | HTTP status code returned by the destination receiver (e.g. 200, 500, or 0 on connection failure). |
deliveries[].response_time_ms | integer | Round-trip latency in milliseconds. |
deliveries[].error_message | string | null | Error description if the delivery failed or timed out. |
deliveries[].payload_snippet | object | null | Metadata snippet containing event type, recipient, and subject. |
deliveries[].created_at | string | ISO 8601 timestamp when the delivery was initiated. |
pagination.total | integer | Total delivery log count matching query criteria. |
pagination.limit | integer | Page limit used for query. |
pagination.offset | integer | Offset applied. |
Standard Event Types
The table below catalogs events dispatched across webhook integrations:
| Event Identifier | Trigger Condition | Common Use Cases |
|---|---|---|
email.received | Inbound message accepted by AliasFleet and evaluated by routing rules. | Parsing transactional receipts, feeding AI assistants, pipeline ingestion. |
email.forwarded | Message successfully delivered to destination inbox. | Delivery audit tracking, latency monitoring. |
email.bounced | Inbound or forwarded message encountered an upstream SMTP delivery failure. | Automated recipient deactivation, bounce alerting. |
email.blocked | Message dropped or rejected due to firewall rules, denylists, or spam scoring. | Security telemetry, threat logging. |