# Outpost: outbound webhooks and event destinations as infrastructure

> Outpost is a Go service from Hookdeck that adds outbound webhooks and event destinations to a platform, with tenant isolation, retries, topics, a customer facing portal and delivery targets ranging from plain webhooks to Kafka, RabbitMQ and cloud queues. It suits a product team adding webhooks for the first time, and it is infrastructure you have to run rather than a library you call.

**hookdeck/outpost** — Open Source Outbound Webhooks and Event Destinations Infrastructure

- Repository: https://github.com/hookdeck/outpost
- Website: https://hookdeck.com/outpost
- Stars: 1,070 · Forks: 73
- Language: Go
- License: Apache-2.0
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/hookdeck-outpost

## What Outpost does

Outpost is production-ready infrastructure for sending webhooks and delivering events from your platform to your customers' systems, and it can be self-hosted anywhere or used as the managed Hookdeck Outpost service.

The problem it addresses is specific and common. A platform that wants to notify its customers when something happens has to write the delivery code, and then it has to live with retries, backoff, signatures, delivery logs, customer complaints and a way for customers to see what happened to their events. That work is identical for every platform, and it is exactly the kind of work that becomes a homegrown subsystem nobody wants to own.

The README lists who it fits, and the list is a better description of the product than the feature list. You are adding outbound webhooks to your platform for the first time. You are replacing a homegrown webhook system that has become a maintenance burden. You want to offer customers more than HTTP callbacks, meaning queues, brokers and buses. You need multi-tenant isolation with a customer facing portal out of the box. Or you want full control over your infrastructure and data.

The last one is the reason this is open source rather than a product, and the compatibility claim is what makes the migration possible. Outpost is backward compatible with your existing payload format, HTTP headers and signatures, so you can drop it into what you already have.

It is written in Go, distributed as a binary and a Docker container, and licensed under Apache-2.0. The runtime has minimal dependencies, which the README lists as Redis or a Redis cluster, PostgreSQL and a supported message queue. The last push to the repository was on 2026-10-14.

## The destination list, and what an event destination is

The headline capability is the range of delivery targets, and it is long enough to be worth listing as the README does.

Out of the box there is support for Webhooks, the Hookdeck Event Gateway, Amazon EventBridge, AWS SQS, AWS Kinesis, AWS S3, GCP Pub/Sub, Azure Service Bus, RabbitMQ, Kafka and Cloudflare Queues.

The distinction between a webhook and the rest matters. A webhook is an HTTP callback to a customer URL, and the hard parts are the delivery semantics. The other targets are queues and brokers, where the event is handed to a system that already has its own retry, ordering and consumer semantics, and where the hard part is the connection, the credentials and the tenancy of the queue.

That is what the Event Destinations link in the README is about. A destination is the target, and the same publish and subscribe model applies whether the target is a URL or a Kafka topic, which is what lets a platform offer a customer their choice of delivery mechanism without building a separate system for each.

The SDKs reflect the same breadth. There is a Go SDK, a Python SDK and a TypeScript SDK, and Outpost also ships with an MCP server, which is the newer addition and the one to look at if you want an agent to drive destination configuration.

The dependency list in go.mod shows the work behind the connectivity. There is the AWS SDK for Go v2 with the EventBridge, Kinesis, S3 and SQS services, the Azure SDK with the Service Bus messaging client, the Google Cloud Pub/Sub client, the RabbitMQ AMQP client, the segmentio Kafka client and the NATS client, plus ClickHouse for the log store.

## Delivery semantics: at least once, retries, fanout and topics

The delivery guarantees are stated plainly, and they are the part to evaluate.

Messages are guaranteed to be delivered at least once and never lost. At least once is a deliberate choice over exactly once, and it is the honest one for webhooks, because a webhook receiver is an arbitrary customer endpoint that may succeed and then time out, and exactly once delivery in that situation is not achievable without cooperation from the receiver.

The at-least-once guarantee comes with the standard consequence, which is that the receiver must be idempotent. That is why the webhook best practices in the feature list include headers for idempotency, timestamp and signature, and signature rotation. The idempotency header is the mechanism that lets a customer deduplicate, and signature rotation exists because a static signing secret is a liability.

Retries are configured per destination, both automatic and manual. A destination that is failing can be retried on demand through the API or from the user portal, which is what turns a support ticket into a button.

Event fanout is the other half. A message sent to a topic is replicated and delivered to multiple endpoints for parallel processing and asynchronous event notifications, so the topic and subscription model is the common publish and subscribe paradigm, which the README says eases adoption and integration into existing systems.

Events can enter through the Outpost API or through a publish queue that Outpost reads from, which is the difference between synchronous request handling and having your own services write to a queue.

Delivery failure alerts close the loop, since the point of knowing a destination is failing is to act before your customers notice.

## Multi-tenancy, the portal and observability

Three features distinguish Outpost from a queue worker with a webhook table.

Multi-tenant support means multiple tenants on a single Outpost deployment, with isolation between them. For a platform, that is the difference between one customer being able to see another's destinations and not, and it is the kind of property that is expensive to retrofit into a homegrown implementation.

The user portal is the customer facing half. Customers can view delivery metrics, manage their destinations, debug delivery issues and observe their event destinations. That is a substantial piece of product that a platform team would otherwise build for each of its customers, and it is the part of Outpost that most reduces support load, because the customer can find the failed delivery themselves.

Observability is standard OpenTelemetry, with standardized traces, metrics and logs, and the dependency list shows the pieces that produce them. There is the OpenTelemetry Redis extra for instrumenting the cache, and a Sentry Go client for error reporting, so the tracing is not only exported but also has a place to surface exceptions.

The log store is a separate concern, and this is the detail that surprises people. The environment reference has a Log Store section with ClickHouse configuration first and Postgres second, and the compose examples include separate files for RabbitMQ and Postgres, which suggests the log store is pluggable.

The reason a log store is needed at all is that the delivery log is the durable record of what was sent to whom, and that record grows quickly and is queried in ways a transactional database is bad at.

## Running it locally with Docker compose

The local quickstart is a clone and a compose stack, and it is deliberately close to how a production deployment looks.

```bash
git clone https://github.com/hookdeck/outpost.git
cd outpost/examples/docker-compose/
cp .env.example .env
```

You update the API_KEY value in the .env file and then start the services with three compose files layered on top of each other.

```bash
docker-compose -f compose.yml -f compose-rabbitmq.yml -f compose-postgres.yml up
```

Outpost is then running on localhost:3333, and the client side variables are simple.

```bash
export OUTPOST_URL=http://localhost:3333
export API_KEY=your_api_key
```

The layered compose files are a nice touch, because they show that the message broker and the database are swappable. The same pattern appears in the environment reference, which has a section per broker with the delivery queue, the log queue and the dead letter queue for RabbitMQ, and the same set for AWS SQS and GCP Pub/Sub.

The environment file is also where the security-relevant configuration sits. The API section has a port, an API key, a JWT secret and an AES encryption secret, alongside the topics the deployment supports, for example a comma separated list of user.created, user.updated and user.deleted. The topics setting is worth understanding, because it defines the vocabulary that destinations subscribe to, and the README describes it as supporting the common publish and subscription paradigm.

Configuration can also come from a YAML file instead of the environment, and the repository ships an example of that format alongside the example environment file.

For a hosted trial, the README also documents a one click deploy to Railway, where the same topics variable and the public URL and generated API key are what you need.

## The build, the tooling and the repository layout

The Makefile is a good map of how the project is developed and shipped.

The build target checks formatting first, and fails with the list of files to fix if gofmt finds anything, before building two binaries with a nomsgpack build tag, the outpost binary and an outpost-server binary. There is a separate goreleaser target, and install puts the binaries into GOPATH.

For development there are up, down and nuke targets that drive a script in the build directory, plus health and smoke targets, and an up/portal target that runs the portal natively with vite hot reload, with a comment explaining that the containerised service is the default and the native target is for the faster development loop.

The test target is the part that shows how the project is tested. The default test run covers the internal packages, and there is a target that starts the infrastructure the default run needs, with a comment explaining that with the destination test flags set it also starts the destination stack, so the test suite can run against real brokers rather than fakes. The dependency list shows both, with miniredis for a Redis substitute in unit tests and the real clients for the integration tests.

The repository layout is broader than a typical service. There are the sdks directory with the three SDKs, a spec-sdk-tests directory, a.speakeasy directory, a loadtest directory, a deployments directory, and an examples directory with a Docker compose setup, Kubernetes manifests, Azure examples, demos and one example per SDK.

There is also an.air.toml for live reloading during development, an AGENTS.md and a CLAUDE.md, and a.cursor directory, which tells you the project has adopted AI tooling in its own development workflow.

## Conclusion

Adopt Outpost if you are adding outbound webhooks to a product and want delivery separated from your request path, with retries, per tenant isolation and a portal your customers can use, because that separation is the entire point of the service. Do not adopt it if your event volume is a trickle and a queue worker would do, since Outpost brings Redis, PostgreSQL and a message broker as runtime dependencies. Before you deploy, copy the example environment file and set the API key, the JWT secret and the AES encryption secret, because those three values are what stand between a demo and a production installation.

## FAQ

### What delivery guarantees does Outpost give?

Messages are guaranteed to be delivered at least once and never lost. Retries are configured per destination and can also be triggered manually through the API or the user portal, and the webhook best practices include headers for idempotency, timestamp and signature, plus signature rotation.

### Which event destinations does Outpost support?

Webhooks, the Hookdeck Event Gateway, Amazon EventBridge, AWS SQS, AWS Kinesis, AWS S3, GCP Pub/Sub, Azure Service Bus, RabbitMQ, Kafka and Cloudflare Queues are supported out of the box, and Go, Python and TypeScript SDKs are available alongside an MCP server.

### What does Outpost need to run?

The runtime has minimal dependencies, which the README lists as Redis or a Redis cluster, PostgreSQL and a supported message queue. Configuration comes from environment variables or a YAML file, and the important secrets are the API key, the JWT secret and the AES encryption secret.

### Can I migrate an existing webhook implementation to Outpost?

Yes. The README states that Outpost is backward compatible with your existing payload format, HTTP headers and signatures, so it can be dropped into an existing implementation, and it lists replacing a homegrown webhook system that has become a maintenance burden as one of the cases it fits.

## Sources

- [hookdeck/outpost on GitHub](https://github.com/hookdeck/outpost)
- [License: Apache-2.0](https://github.com/hookdeck/outpost/blob/main/LICENSE)
- [Project website](https://hookdeck.com/outpost)
- [README](https://github.com/hookdeck/outpost/blob/main/README.md)
- [Releases](https://github.com/hookdeck/outpost/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/hookdeck-outpost
