Publishing Events

Once your first tenant and destination are created, you can publish events. Events are evaluated against all registered destinations and delivered to each eligible one.

Publishing Methods

Events can be published in two ways:

1. Via the Publish API endpoint — An HTTP POST request to your Outpost instance. Simple to integrate, but adds a dependency on the Outpost API being available.

2. Via a message queue — Publish events directly to the message queue that Outpost consumes. Higher durability since there's no additional dependency beyond the queue itself.

If you already publish events to a supported message queue, refer to the relevant guide:

Event Structure

{
  "id": "evt_123",
  "tenant_id": "your-tenant-id",
  "destination_id": "dest_456",
  "topic": "user.created",
  "eligible_for_retry": true,
  "time": "2024-06-01T08:23:36.082374Z",
  "metadata": {
    "source": "signup-service"
  },
  "data": {
    "user_id": "usr_789",
    "email": "user@example.com"
  }
}
FieldRequiredDescription
idNoUnique event ID. If omitted, generated by hashing topic, data, and timestamp. Providing an ID enables idempotency.
tenant_idYesThe tenant to deliver the event to. Must match an existing tenant.
destination_idNoForce delivery to a specific destination, bypassing topic matching.
topicNoThe event topic. Must match one of the configured topics if set. Assumed to match all topics if omitted.
eligible_for_retryNoWhether to automatically retry failed deliveries. Defaults to true.
timeNoISO 8601 timestamp of the event.
metadataNoArbitrary key-value pairs. For webhooks, translated to HTTP headers.
dataNoThe event payload — freeform JSON.

Publish API

curl --location 'https://api.outpost.hookdeck.com/2025-07-01/publish' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_KEY>' \
--data '{
  "tenant_id": "your-tenant-id",
  "topic": "user.created",
  "eligible_for_retry": true,
  "data": {
    "user_id": "usr_789",
    "email": "user@example.com"
  }
}'

Replace <API_KEY> with your Outpost API key.

When self-hosting Outpost, replace the API root URL with your own deployment URL, e.g., https://outpost.your-domain.com/api/v1/publish.

Metadata and Headers

The metadata field in published events is merged with the destination's delivery_metadata before delivery. The merge priority is:

system metadata (event-id, topic, timestamp)
  < destination's delivery_metadata
    < event metadata (highest priority)

For webhook destinations, merged metadata is translated into HTTP headers. This lets you:

  • Set static headers (e.g., x-api-key) on the destination via delivery_metadata
  • Override or add dynamic headers per event via the event's metadata field

For destinations that don't natively support metadata (e.g., S3), it is included in the event payload or object metadata.

Event Fanout

When an event is published, Outpost evaluates it against all tenant destinations. Events matching multiple destinations are independently delivered to each — modifications to one delivery do not affect others.

Evaluating Topics Before Publishing

Each call to GET /api/v1/tenants/:tenant_id returns a topics array listing all topics currently in use across that tenant's destinations. You can cache this value in your application and use it to skip the publish call entirely when no destination would match a given topic.

You can also subscribe to the tenant.subscriptions.updated Operator Events topic to receive an event when the tenant's subscribed topics change.

While this is optional, it is strongly recommended to perform pre-filtering on topics. This limits the network calls from your application (reducing operation latency) and reduces resource consumption on Outpost services.

Delivery guarantee

Once an event is ingested by Outpost, delivery to eligible destinations has an at-least-once guarantee. However, it is your responsibility to implement at-least-once publishing to the Outpost API or the message queue that Outpost consumes. This implies that your application needs to be able to retry publishing failures if such guarantee is a requirement.