Operator Events
Operator events let you subscribe to lifecycle events from your Outpost deployment, including delivery failures, destination disabling, retry exhaustion, and subscription changes.
Configuration
Enable operator events by specifying topics and configuring a sink.
Topics
Configure operator event topic subscriptions through Hookdeck Monitoring settings or Config API.
Set OPERATOR_EVENTS_TOPICS to a comma-separated list of topics:
OPERATOR_EVENTS_TOPICS=alert.destination.disabled,alert.attempt.exhausted_retries
Use * to subscribe to all topics. A wildcard subscription also includes topics added in future versions, so upgrading Outpost can change what your sink receives. Prefer an explicit topic list unless your sink is sized for per-attempt volume.
Available topics:
| Topic | Trigger |
|---|---|
alert.destination.consecutive_ | Consecutive failure count reaches 50%, 70%, 90%, or 100% of ALERT_ |
alert.destination.disabled | Destination auto-disabled at 100% failure threshold |
alert.attempt.exhausted_ | Delivery exhausts all retry attempts (at most one alert per destination within the deduplication window) |
attempt.success | Every successful delivery attempt |
attempt.failed | Every failed delivery attempt, including retries |
tenant.subscription.updated | Destination created/updated/deleted and tenant topics or destination count changed |
Operator event delivery and topic selection are managed through Hookdeck Monitoring settings.
If OPERATOR_EVENTS_TOPICS is empty or unset, operator events are disabled. If topics are configured but no sink is set, Outpost logs a warning and drops operator events.
Sinks
Configure the operator events sink in Hookdeck Monitoring settings or through the API.
Managed Outpost delivers operator events through Outpost itself, so the sink can be any of the supported destination types. Configuration and delivery format, including signatures, follow the documentation for the chosen destination type.
Configure one sink to receive events. If more than one is configured, Outpost uses the first of HTTP, AWS SQS, GCP Pub/Sub and RabbitMQ.
Four sink types are supported:
HTTP
Sends events as POST requests to a URL. If OPERATOR_ is set, requests are signed with HMAC-SHA256.
OPERATOR_EVENTS_HTTP_URL=https://example.com/outpost-events
OPERATOR_EVENTS_HTTP_SIGNING_SECRET=your-secret
The HTTP sink sends signatures in X-Outpost-Signature:
- Format:
v0=<hex> - Algorithm: HMAC-SHA256 over the raw JSON body
Verification example:
import hashlib
import hmac
expected = hmac.new(signing_secret.encode(), body, hashlib.sha256).hexdigest()
assert signature_header == f"v0={expected}"
AWS SQS
OPERATOR_EVENTS_AWS_SQS_QUEUE_URL=https://sqs.us-east-1.amazonaws.com/123456789/outpost-events
OPERATOR_EVENTS_AWS_SQS_ACCESS_KEY_ID=AKIA...
OPERATOR_EVENTS_AWS_SQS_SECRET_ACCESS_KEY=...
OPERATOR_EVENTS_AWS_SQS_REGION=us-east-1
OPERATOR_EVENTS_AWS_SQS_ENDPOINT= # optional, for local dev
GCP Pub/Sub
OPERATOR_EVENTS_GCP_PUBSUB_PROJECT_ID=my-project
OPERATOR_EVENTS_GCP_PUBSUB_TOPIC_ID=outpost-events
OPERATOR_EVENTS_GCP_PUBSUB_CREDENTIALS={"type":"service_account",...}
RabbitMQ
OPERATOR_EVENTS_RABBITMQ_SERVER_URL=amqp://guest:guest@localhost:5672
OPERATOR_EVENTS_RABBITMQ_EXCHANGE=outpost-events
Event Envelope
All operator events share this envelope:
{
"id": "unique-event-id",
"topic": "alert.destination.consecutive_failure",
"time": "2025-06-01T12:00:00Z",
"deployment_id": "my-deployment",
"tenant_id": "tenant_123",
"data": {}
}
| Field | Description |
|---|---|
id | Unique event identifier |
topic | Event topic |
time | ISO 8601 timestamp |
deployment_id | Deployment ID (if configured) |
tenant_id | Tenant associated with the event (if applicable) |
data | Topic-specific payload |
Event Payloads
alert.destination.consecutive_ failure
Emitted when a destination reaches 50%, 70%, 90%, or 100% of ALERT_.
{
"tenant_id": "tenant_123",
"event": {},
"attempt": {},
"destination": {
"id": "des_456",
"tenant_id": "tenant_123",
"type": "webhook",
"topics": ["order.created"],
"disabled_at": null
},
"consecutive_failures": {
"current": 50,
"max": 100,
"threshold": 50
}
}
alert.destination.disabled
Emitted when a destination is auto-disabled after reaching the 100% threshold (only when ALERT_).
{
"tenant_id": "tenant_123",
"destination": {
"id": "des_456",
"tenant_id": "tenant_123",
"type": "webhook",
"topics": ["order.created"],
"disabled_at": "2025-06-01T12:00:00Z"
},
"disabled_at": "2025-06-01T12:00:00Z",
"reason": "consecutive_failure",
"event": {},
"attempt": {}
}
alert.attempt.exhausted_ retries
Emitted when a delivery exhausts all retry attempts. At most one alert per destination within ALERT_; the alert payload carries the first exhausted event in the window. Set the window to 0 to alert on every exhaustion.
{
"tenant_id": "tenant_123",
"event": {},
"attempt": {},
"destination": {
"id": "des_456",
"tenant_id": "tenant_123",
"type": "webhook",
"topics": ["order.created"],
"disabled_at": null
}
}
attempt.success / attempt.failed
Emitted once per delivery attempt, keyed by outcome. The two topics share one payload shape; attempt.status carries the outcome. attempt.failed fires on every failed attempt including retries — use attempt.attempt_number and event.eligible_for_retry to distinguish retryable failures from final ones.
{
"tenant_id": "tenant_123",
"event": {
"id": "evt_789",
"tenant_id": "tenant_123",
"destination_id": "des_456",
"matched_destination_ids": ["des_456"],
"topic": "order.created",
"eligible_for_retry": true,
"time": "2025-06-01T12:00:00Z",
"metadata": {},
"data": {
"order_id": "ord_123"
}
},
"attempt": {
"id": "att_abc",
"tenant_id": "tenant_123",
"event_id": "evt_789",
"destination_id": "des_456",
"destination_type": "webhook",
"attempt_number": 2,
"manual": false,
"status": "failed",
"time": "2025-06-01T12:00:05Z",
"code": "500",
"latency_ms": 1502,
"response_data": {
"status": 500,
"body": "internal server error"
}
},
"destination": {
"id": "des_456",
"tenant_id": "tenant_123",
"type": "webhook",
"topics": ["order.created"],
"disabled_at": null
}
}
An attempt.success payload is identical except attempt.status is "success" and code/response_data carry the destination's response (for a webhook, the HTTP status and body). For network-level failures, code is an error class such as connection_refused or dns_error instead of an HTTP status.
The alert payloads above carry the same event and attempt objects, elided for brevity.
tenant.subscription.updated
Emitted when destination changes affect tenant-level subscribed topics or destination count.
{
"tenant_id": "tenant_123",
"topics": ["order.created", "order.updated"],
"previous_topics": ["order.created"],
"destinations_count": 3,
"previous_destinations_count": 2
}
Delivery Guarantees
alert.* and attempt.* topics are delivered with an at-least-once guarantee. For other topics (e.g. tenant.subscription.updated), delivery is on a best-effort basis with up to 3 attempts. Consumers should deduplicate using the event id.
Related Configuration
Alert threshold and destination auto-disable behavior are managed through Hookdeck Monitoring settings.
| Config | Description | Default |
|---|---|---|
ALERT_ | Number of consecutive failures before the 100% threshold | 100 |
ALERT_ | Auto-disable destinations at the 100% threshold | false |
ALERT_ | Deduplication window for exhausted retry alerts (seconds) | 3600 |