Why Signalbin Replaced Forwarding Rules With Destinations

Signalbin's forwarding rules mixed selection and delivery. Replacing them with destinations made fan-out, replay, health, and failure behavior explicit.

Signalbin's original forwarding rules tried to answer two questions at once: which captured requests should be sent, and where should they go? Replacing them with destinations removed the selection language and made delivery behavior explicit. Every enabled destination receives its own copy.

This was a substantial rewrite, not a rename. The first replacement commit changed about 3,700 lines because the old concept had spread through storage, APIs, the UI, delivery code, tests, and documentation.

Rules made ordinary fan-out harder to explain

A rule suggests matching, ordering, and precedence. Those concepts are valuable when users actually need conditional routing. Signalbin's common case was simpler: capture a webhook, retain it for inspection, then relay it to one or more known systems.

Destinations model that case directly. An endpoint can have up to ten HTTP destinations. Each one has a URL, method override, header additions and removals, an enabled flag, and delivery health. Enabled destinations fan out concurrently and do not compete with one another.

That model makes several product questions answerable without reading a rule engine. Disabling one destination does not affect the others. One failed delivery does not suppress the remaining fan-out. Replaying an event uses the endpoint's currently enabled destinations and their current configuration.

The Signalbin endpoints and destinations guide documents the behavior as a delivery list rather than a routing language, which matches what the system now guarantees.

Failure behavior became part of the object

Once a destination was a durable object, it could own delivery state. Signalbin records attempts against the destination, tracks consecutive failures, and distinguishes reachability from acceptance. A 4xx response means the remote server was reached and rejected the payload, so it resets connection-health failures. Transport errors and 5xx responses can be retried up to three attempts within a shared 30 second fan-out budget.

The budget matters because ten destinations with independent retries can otherwise keep the ingest request alive unpredictably. Signalbin detaches delivery from the sender after capture, caps concurrent fan-out across the server, and records each result for later inspection.

A relay marker header also prevents an endpoint from recursively feeding Signalbin back into itself. This guard belongs to delivery regardless of whether the request is live or replayed, so both paths use the same destination pipeline.

The simpler concept exposed more operations

The old rule abstraction made create, update, test, and replay semantics depend on matching configuration. Destinations produced a smaller set of verbs that mapped cleanly into the web UI, REST API, and MCP tools: list, create, update, delete, enable, and replay.

The cost was migration work across every interface. The benefit is that each layer now names the same object and can test the same invariant: every enabled destination gets one independent attempt for a captured request.

A sophisticated abstraction is useful only when its sophistication corresponds to a user decision. Signalbin did not need a rule engine to describe unconditional fan-out. Calling the targets destinations made the delivery contract smaller, then gave retries, health, replay, and loop prevention a clear place to live.