Guides

Upgrade to v0.16

This guide covers breaking changes and migration steps when upgrading from v0.15 to v0.16.

Breaking Changes Overview

ChangeImpactAction Required
Webhook signing secret prefix changedNew webhook destination signing secretsSet DESTINATIONS_WEBHOOK_SIGNING_SECRET_TEMPLATE to preserve previous behavior
Event destination_id replaced with matched_destination_idsEvent API responses and queriesUpdate code that reads destination_id from events to use matched_destination_ids
Delivery metadata timestamp formatConsumers of delivery metadata timestamp fieldUpdate timestamp parsing from Unix seconds to ISO 8601
Response data body stored as raw stringConsumers of response_data.bodyUpdate code that treats response_data.body as a parsed JSON object
Alert callbacks replaced by operator eventsUsers of ALERT_CALLBACK_URLMigrate to OPERATOR_EVENTS_* config

Webhook Signing Secret Prefix Changed

The default signing secret template for new webhook destinations changed from {{.RandomHex}} to whsec_{{.RandomHex}}. New destinations will now have signing secrets prefixed with whsec_ (e.g., whsec_a1b2c3...).

Existing destinations keep their current signing secrets — this only affects newly created destinations.

Preserving previous behavior

To keep generating unprefixed secrets, set this config var:

DESTINATIONS_WEBHOOK_SIGNING_SECRET_TEMPLATE={{.RandomHex}}

Event destination_id Replaced with matched_destination_ids

The destination_id field has been removed from events and replaced with matched_destination_ids, an array of destination IDs that the event was actually routed to.

API response change

v0.15:

{ "id": "evt_123", "destination_id": "des_456", "topic": "order.created" }
json

v0.16:

{ "id": "evt_123", "matched_destination_ids": ["des_456", "des_789"], "topic": "order.created" }
json

Filtering

You can now filter events by destination: GET /events?destination_id=des_456. This filters using the new matched_destination_ids field.

No data backfill

Existing events created before the upgrade will have an empty matched_destination_ids array. Only events published after the upgrade will have this field populated.

Action: Update any code that reads event.destination_id to use event.matched_destination_ids. If you need a single destination ID, use the first element of the array.

Delivery Metadata Timestamp Format

The timestamp field in delivery metadata has changed from Unix seconds to ISO 8601 format.

v0.15:

timestamp: 1609459200

v0.16:

timestamp: 2021-01-01T00:00:00Z

Action: Update any code that parses the timestamp metadata field to handle ISO 8601 (RFC 3339) format instead of Unix seconds.

Response Data Body Stored as Raw String

The response_data.body field in delivery attempts is now always stored as a raw string, regardless of the destination's response content type. Previously, JSON response bodies were parsed into objects.

API response change

v0.15 — JSON response body was a parsed object:

{ "status": 200, "body": { "id": "usr_123", "status": "created" } }
json

v0.16 — body is the raw response string:

{ "status": 200, "body": "{\"id\":\"usr_123\",\"status\":\"created\"}" }
json

Non-JSON responses are unchanged (already stored as strings).

Database migration

The attempts.response_data column is migrated from JSONB to TEXT (migration 000009). This migration runs automatically on startup. Any direct SQL queries that use JSON operators on response_data (e.g., response_data->'body'->>'key') will need to be updated.

Action: Update any code that reads response_data.body as a structured object. If you need the parsed object, parse the string with JSON.parse() (or equivalent) on the client side.

Alert Callbacks Replaced by Operator Events

The ALERT_CALLBACK_URL config has been removed. Alert notifications are now handled by the new operator events system, which supports multiple sink types and additional event topics.

Migration

If you were using ALERT_CALLBACK_URL to receive alert callbacks via HTTP, migrate to the operator events HTTP sink:

v0.15:

ALERT_CALLBACK_URL=https://example.com/alerts

v0.16:

OPERATOR_EVENTS_TOPICS=* OPERATOR_EVENTS_HTTP_URL=https://example.com/alerts OPERATOR_EVENTS_HTTP_SIGNING_SECRET=your-secret

The HTTP sink signs payloads with HMAC-SHA256 and sends the signature in the X-Outpost-Signature header (format: v0=<hex>).

New sink options

In addition to HTTP, operator events can be sent to:

  • AWS SQSOPERATOR_EVENTS_AWS_SQS_QUEUE_URL, OPERATOR_EVENTS_AWS_SQS_ACCESS_KEY_ID, OPERATOR_EVENTS_AWS_SQS_SECRET_ACCESS_KEY, OPERATOR_EVENTS_AWS_SQS_REGION
  • GCP Pub/SubOPERATOR_EVENTS_GCP_PUBSUB_PROJECT_ID, OPERATOR_EVENTS_GCP_PUBSUB_TOPIC_ID, OPERATOR_EVENTS_GCP_PUBSUB_CREDENTIALS
  • RabbitMQOPERATOR_EVENTS_RABBITMQ_SERVER_URL, OPERATOR_EVENTS_RABBITMQ_EXCHANGE

Event topics

Use OPERATOR_EVENTS_TOPICS=* for all topics, or specify a comma-separated list:

  • alert.destination.consecutive_failure — emitted at 50%, 70%, 90%, and 100% failure thresholds
  • alert.destination.disabled — emitted when a destination is auto-disabled
  • alert.attempt.exhausted_retries — emitted when delivery exhausts all retry attempts
  • tenant.subscription.updated — emitted on destination create/update/delete/disable/enable

Alert default changes

The alert thresholds have also changed:

Settingv0.15 Defaultv0.16 Default
Consecutive failure count20100
Auto-disable destinationtruefalse

If you relied on the previous defaults, set them explicitly:

ALERT_CONSECUTIVE_FAILURE_COUNT=20 ALERT_AUTO_DISABLE_DESTINATION=true

Other Notable Changes

These changes are not breaking but may be useful to know about.

DELETE /destinations response

DELETE /tenants/{tid}/destinations/{did} now returns { "success": true } instead of the full destination object, matching the behavior of DELETE /tenants/{tid}.

Empty webhook header prefix

You can now disable the webhook header prefix by setting it to whitespace (e.g., DESTINATIONS_WEBHOOK_HEADER_PREFIX=" "). This results in headers like signature instead of x-outpost-signature.

Upgrade Checklist

  1. Before upgrading:

    • Decide whether to adopt whsec_ prefixed signing secrets or preserve previous format (set DESTINATIONS_WEBHOOK_SIGNING_SECRET_TEMPLATE if preserving)
    • Update code that reads event.destination_id to use event.matched_destination_ids
    • Update any timestamp metadata parsing from Unix seconds to ISO 8601
    • Update code that reads response_data.body as a parsed object — it is now a raw string
    • If using ALERT_CALLBACK_URL, migrate to OPERATOR_EVENTS_* config
    • Review alert default changes (consecutive failure count: 20→100, auto-disable: true→false) and set explicitly if needed
    • Update SDK dependencies to the latest version
  2. Upgrade:

    • Update Outpost to v0.16 and restart — database migrations run automatically on startup
  3. After upgrading:

    • Verify event queries and filters work with matched_destination_ids