Event Drains

Event drains stream delivery-lifecycle events out of Hooksbase into external observability or journaling systems. Use them when you need a near-real-time feed of delivery state changes outside the dashboard itself.

Drain model

Drains subscribe to delivery lifecycle events, not arbitrary webhook payloads. The current event types are:

  • delivery.created
  • attempt.completed
  • delivery.succeeded
  • delivery.failed
  • delivery.dlq_entered

Tiering:

  • Free and Starter cannot create drains
  • Pro allows one drain
  • Business allows three drains
  • Enterprise is effectively unbounded

You can optionally scope a drain to a subset of webhook IDs instead of the whole project.

Where this lives

Event drain management is dashboard-first, and the dashboard is the preferred surface. Open the event drains section from project settings to:

  • create a drain (pick a sink type, provide credentials, choose event types, optionally scope to specific webhooks)
  • inspect the drain's current status, recent failure count, and last error
  • pause or resume a drain
  • edit sink configuration and credentials
  • delete a drain

There is also a low-level project-authenticated route family under /v1/app/event-drains. It is not wrapped by the SDK or CLI and is intended for raw HTTP automation when the dashboard is not the right surface.

Sink types and events

Supported sink types:

  • webhook — POST each event to an HTTPS URL, optionally signed
  • axiom — forward events to an Axiom dataset
  • datadog — forward events to Datadog Logs
  • object_storage — write one JSON object per event to S3-compatible storage
  • otlp_http — emit events as OpenTelemetry Logs over OTLP/HTTP JSON

Behavior notes:

  • webhook drains can include an optional signing secret; Hooksbase sends the HMAC in x-signature-sha256
  • object-storage drains write one JSON object per drain event
  • OTLP HTTP drains are logs-only, JSON-only, and do not batch or backfill

Because drains are delivery-lifecycle observers, they pair naturally with operator alerting: drains give you raw event streams, while operator alerting gives you customer-facing incident state and routing.

Raw HTTP examples

Create, patch, and resume require Pro+. List, get, pause, and delete are still project-authenticated, but lower-tier projects do not process active drains.

Create a webhook drain

curl https://api.hooksbase.com/v1/app/event-drains \
  -H "Authorization: Bearer swk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Delivery stream",
    "sinkType": "webhook",
    "sinkConfig": {
      "url": "https://observability.example.com/hooksbase",
      "signingSecret": "drain-secret"
    },
    "eventTypes": [
      "delivery.created",
      "attempt.completed",
      "delivery.failed"
    ],
    "filterWebhookIds": ["wh_123"]
  }'

201 response

{
  "id": "drain_123",
  "projectId": "proj_123",
  "name": "Delivery stream",
  "status": "active",
  "sinkType": "webhook",
  "eventTypes": [
    "delivery.created",
    "attempt.completed",
    "delivery.failed"
  ],
  "filterWebhookIds": ["wh_123"],
  "consecutiveFailures": 0,
  "lastSuccessAt": null,
  "lastFailureAt": null,
  "createdAt": 1766600000000,
  "updatedAt": 1766600000000
}

Patch event types or sink config

curl -X PATCH https://api.hooksbase.com/v1/app/event-drains/drain_123 \
  -H "Authorization: Bearer swk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "eventTypes": [
      "delivery.created",
      "attempt.completed",
      "delivery.succeeded",
      "delivery.failed",
      "delivery.dlq_entered"
    ],
    "sinkConfig": {
      "url": "https://observability.example.com/hooksbase-v2"
    }
  }'

Pause, resume, and delete

curl -X POST https://api.hooksbase.com/v1/app/event-drains/drain_123/pause \
  -H "Authorization: Bearer swk_..."

curl -X POST https://api.hooksbase.com/v1/app/event-drains/drain_123/resume \
  -H "Authorization: Bearer swk_..."

curl -X DELETE https://api.hooksbase.com/v1/app/event-drains/drain_123 \
  -H "Authorization: Bearer swk_..."

See raw HTTP examples for the same route family alongside the other raw-only public routes.

Patch and failure behavior

When editing an existing drain, the dashboard uses merge semantics for credentials:

  • leaving object-storage credentials blank keeps the existing encrypted values
  • optional object-storage fields can be cleared with an explicit empty value
  • leaving OTLP headers blank keeps the saved headers
  • clearing OTLP headers is an explicit action in the UI

Failure behavior:

  • a drain moves to failed after 10 consecutive failures
  • resume returns it to active and resets the consecutive-failure counter
  • paused or failed drains can still be inspected, edited, resumed, or deleted
  • drain failures can surface into operator issues such as drain_paused and drain_degraded

Common mistakes

  • Assuming drains stream original inbound payloads instead of delivery lifecycle events.
  • Assuming event drains are wrapped by the SDK or CLI. Use the dashboard or raw HTTP against /v1/app/event-drains.
  • Forgetting that editing a drain's credentials preserves saved values unless you explicitly clear them.
  • Expecting drains to replace operator alerting. They serve different operator workflows.
  • Treating the dashboard's browser traffic as an integration contract.

Was this page helpful?