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"
}
}
| Field | Required | Description |
|---|---|---|
id | No | Unique event ID. If omitted, generated by hashing topic, data, and timestamp. Providing an ID enables idempotency. |
tenant_id | Yes | The tenant to deliver the event to. Must match an existing tenant. |
destination_id | No | Force delivery to a specific destination, bypassing topic matching. |
topic | No | The event topic. Must match one of the configured topics if set. Assumed to match all topics if omitted. |
eligible_for_retry | No | Whether to automatically retry failed deliveries. Defaults to true. |
time | No | ISO 8601 timestamp of the event. |
metadata | No | Arbitrary key-value pairs. For webhooks, translated to HTTP headers. |
data | No | The 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 viadelivery_metadata - Override or add dynamic headers per event via the event's
metadatafield
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.