Dashboard v0.2.0
-
Every section of a project now has a two-key "go to" shortcut. Press
G, release it, thenOfor Overview,Sfor Sources,Dfor Destinations,Tfor Templates,Xfor Transforms,Ffor Filters,Efor Events,Mfor Metrics, or,for Settings. -
The command palette shows those two keys beside each navigation command, one chip per press, so the sequences are discoverable without memorising them.
-
The
Gshortcuts stay out of the way: nothing happens while you are typing in a field, while a dialog or menu is open, or outside a project — and an unfinished sequence clears itself after a moment, leaving the next key to behave normally. -
Leaving an editor with unsaved changes now asks you to confirm from the sidebar, the command palette, and the navigation shortcuts too, not only from the editor's Back button.
-
Routing rules now open as a full page instead of a dialog, so a link's configuration has its own URL you can bookmark or share.
-
Rules are listed as collapsed rows. Each row summarises what the rule matches on, whether it delivers or skips, and every override it applies — so a long rule set is readable without opening anything. Rules that match using a named filter say so, rather than guessing an outcome the filter decides.
-
Rules can be reordered with the up and down arrows on a row, or with
Alt+↑/↓on a focused rule. Since the first matching rule wins, reordering changes which rule takes effect. -
A rule can be given an optional label, shown on its collapsed row in place of "Rule 1", "Rule 2", and so on.
-
The routing editor is keyboard-operable end to end:
↑/↓move between rules,EnterorSpaceexpands one, andCtrl+S(⌘Son macOS) saves without leaving the page. -
Condition field boxes now suggest payload paths and header names taken from the source's recent events. Sources with no events yet get a plain text box, as before.
-
The condition preview no longer shows a regex pattern or a comma-separated list as if it were a literal value to match.
-
The "matches regex" operator now notes that patterns use Go's RE2 syntax, which has no backreferences or lookaround.
-
Saving a rule set that the server rejects now shows the actual reason instead of a generic failure message.
-
Disconnecting a connected source now clears its cached destination links, filters and event status, so a source added back under the same name no longer shows the old one's configuration.
-
The routing editor has a Test panel. Paste a sample payload, or pick one of the source's recent events to fill in its payload and headers, then run your rules against it — including edits you have not saved yet. Nothing is stored and no delivery is sent.
-
The result names the rule that matched, or says that no rule matched and the link defaults apply, and calls out when the winning rule skips delivery. It lists the template, transform, headers, delay and thread the rule applies — including the case that catches people out, where a matching rule with no template selected resets the template rather than inheriting the link's default.
-
Each rule shows why it did or did not match, condition by condition, with the value found at each field path. Rules that were never reached because an earlier rule already won, and rules that can never match because they have no conditions, are labelled as such.
-
Invalid regex patterns now surface before you save. Patterns use Go's RE2 syntax, which the browser cannot validate, so a typo previously just stopped matching anything with no warning. Unknown operators, malformed field paths and missing reusable filters are flagged the same way. These notes explain a result — they never block saving.
-
Viewers can run the test panel too, since it only evaluates and changes nothing.
-
Lists across the dashboard now navigate with the keyboard: press ArrowDown and ArrowUp to move between rows, and Home or End to jump to the first or last one. This works on events, templates, transforms, filters, projects, destinations, API keys, notification rules and the Slack channel picker.
-
A list's primary controls now share a single roving tab stop, so Tab enters the list at the row you last used instead of at the top; a row's other buttons stay in the tab order. The events table's rows, previously unreachable by keyboard entirely, are now focusable.
-
Events can now be opened from the keyboard: press Enter on a highlighted event row to open its detail, and Space to select it for bulk actions such as replay.
-
Arrow keys held with Alt, Shift, Ctrl or Cmd are left to your browser, and an arrow press at the top or bottom of a list scrolls the page as usual instead of wrapping around.
Keyboard shortcuts are now discoverable and customizable, and templates, transforms, and filters can be attached to routes straight from their editors.
- A shortcuts reference sheet opens with
Ctrl+/(⌘/on macOS) or the new keyboard button in the header: every shortcut in the app grouped by category, with shortcuts that don't apply on the current page dimmed rather than hidden, plus the fixed in-context keys such as list navigation and the AI dialogs' submit key. - Any shortcut can be rebound or unbound from the new Keyboard shortcuts card in account settings: click a shortcut, press the new combination, done. Combinations that would collide — with another action, a navigation sequence, browser-reserved keys, text-editing keys, or the keys lists themselves use — are refused with the conflict named. Custom bindings are stored in your browser, take effect immediately in every tooltip and menu, and can be reset per action or all at once.
- The template, transform, and filter editors gain an Attach button: choose the source → destination links the open resource should serve, see what each link currently uses and how many already use it as their default, and get a warning when attaching would replace something. The dialog stays open so several links can be wired in one visit. A filter attached to a route gates every event on that link before its routing rules run; templates and transforms set the link default that routing rules may override.
- Confirmation dialogs now always close when you confirm. Previously, confirming an action whose request failed (for example revoking an API key while offline) left the dialog open with no feedback, inviting repeat clicks.
Templates, transforms, and filters can now store a set of example payloads, and AI generation reasons over the whole set instead of a single sample.
- Each editor gains a Sample set section: keep up to 10 real event payloads alongside the active sample, add them from a keyboard-navigable picker over the events your project received in the last 30 days (
Spaceselects,Enteradds the selection — or the highlighted event when nothing is selected) or save the payload currently in the editor, and swap any stored sample in as the active one. Sample sets ride the editor's normal save, and events already in the set are marked so you can't add them twice. - Generate with AI now grounds its output in your stored samples as well as the active one. Template paths that only some of your events carry are kept (and can be guarded with conditionals) instead of being "corrected" away, filter generation sees each event's payload and headers together, and each editor spells out what a generation will read: the payload in the editor, however many samples your set holds, or — with both empty — that it has nothing but your description to work from. A set too large for one request is trimmed by dropping whole samples, so the output stays grounded in complete events. Transform generation also handles large payloads more robustly.
- Create from event now seeds the new template, transform, or filter with that event as its first stored sample, so the first AI generation has real data without a trip to the picker. An unusually large event is skipped for seeding and the resource is still created.
- The transforms AI prompt bar's
Ctrl+Enter(⌘Enteron macOS) submit chord — which matches the other AI dialogs — is now documented in the shortcuts reference, and AI error messages surface more reliably. - More signing headers are stripped before header samples are stored, and the stripping is now applied when a stored sample is read back as well as when it is captured.
- The shortcuts reference sheet's In context section now covers the attach-link picker and the new recent-events picker, and no longer lists
Escas an AI-dialog key (closing a dialog withEscworks everywhere, not just there). - Docs: the sidebar toggle
Ctrl+B(⌘B), each AI dialog'sCtrl+Entersubmit key, and a note thatCtrl+Kno longer focuses the events search (press/instead) are now documented where you'd look for them.
Dispatch has a new visual identity.
- New mark. The logo is now a wordmark whose "i" is dotted with a packet — the same shape, lifted out on its own, is the app icon. It replaces the previous hub-and-spoke icon everywhere it appeared: the dashboard, the browser tab, the docs site, and the preview image shown when a Dispatch link is shared. The logo tiles inside the app frame the packet exactly as the browser-tab icon does, so the mark reads identically at every size. The dashboard sidebar, the site header and footer, and the sign-in pages all show the full horizontal lockup — the icon beside the wordmark — and the sidebar collapses back to the icon alone when minimized.
- New colour. The orange accent is gone, replaced by a teal one across the dashboard in both light and dark mode, on the marketing and docs sites, and in the emails Dispatch sends. Every text-on-colour pairing was measured against WCAG contrast minimums rather than assumed readable.
- Status colours keep their meaning. Delivered, failed, pending, filtered and warning states read exactly as before, including the amber band on usage meters. The metrics charts keep their own set of distinct series colours rather than shades of the brand, so a colour change can't repaint the meaning of a chart or a status badge. A usage meter's healthy fill follows the new accent.
- Docs: the example embed colour in the Discord, Slack and message-template samples was still the previous brand colour. The samples you copy now carry the current one.
Generate routing rules with AI, and create resources from an event with AI-generated content.
The routing editor gains Generate rules with AI (Ctrl+Alt+P): describe your routing in plain English and Dispatch drafts the rules — grounded on the source's recent events so conditions reference fields your payloads actually have, and aware of your existing rules so new ones complement rather than repeat them. Generated rules can set labels, conditions, skip, and template/transform assignments from your project; they are shown in a review pane first — with generated regexes validated automatically — and applied after your existing rules, fully editable, with nothing stored until you save.
The Create from event dialog gains an optional description field: fill it in and the new template, transform, or filter is created already carrying AI-generated content grounded on that event — a filter arrives with real conditions instead of an empty list. Leave it blank for the previous behavior. If generation fails, nothing is created and the error is shown in the dialog.
-
Keyboard shortcuts are now managed centrally, so every shortcut behaves the same way across the dashboard.
-
Shortcut hints on buttons and in tooltips now show the right keys for your platform, and are announced to screen readers.
-
Pressing
/focuses the events search on every keyboard layout, including those where/needs Shift. -
Cmd/Ctrl+K no longer focuses the events search — press
/instead. -
The Save and Run test shortcuts no longer fire when their buttons are unavailable.
-
Holding a shortcut down no longer repeats it, and a shortcut pressed inside a dialog or menu no longer acts on the page behind it.
-
The routing rules editor now offers the "matches regex" operator, so a rule condition can match a field against a pattern instead of a literal value.
-
Fixed the overview page's recent-events list and the events table rendering incorrectly (duplicated or missing rows) when a webhook was redelivered with an identical payload.
-
A routing rule set is now capped at 50 rules, with up to 50 conditions and 50 custom headers per rule, plus sensible length limits on condition fields and header values.
-
Added a command palette. Press
Cmd/Ctrl+Kanywhere in the dashboard — or click the new palette button in the header — to search every action available on the page you're on and run it without touching the mouse. Each command shows its own shortcut, so the palette doubles as the shortcut reference. -
Commands that exist but can't run yet — Save on a form with no unsaved changes — now stay listed and greyed out instead of disappearing, so the shortcut stays discoverable.
-
Inside a project the palette also offers navigation commands for Overview, Sources, Destinations, Templates, Transforms, Filters, Events, Metrics, and Settings.
-
Cmd/Ctrl+Alt+Pnow opens AI generation in the template and filter editors too, matching the events page and the transform editor. -
Fixed the AI search box on the events page inserting a newline as well as generating when you pressed
Cmd/Ctrl+Enter. -
Creating a template, transform, or filter from an event now offers an optional second step that attaches the new resource to one of your existing source → destination routes, so it goes into service without a separate trip to the sources page. Pick a route with the arrow keys or the mouse; paused routes are listed too, and you can see which template an attach would replace before confirming.
-
The editor you land in now shows a "Created from event" banner linking back to the event you started from, so you can move between the sample data and the real event while you work. Dismiss it when you're done.
-
Editor links opened from an event now use your project's name in the URL instead of its internal id.
-
Linking a destination to a source now rejects templates, transforms, filters, and destinations belonging to a different project — including ones referenced from inside a routing rule — instead of accepting them.
-
New accounts are set up automatically on first sign-in: a default organization and project are created and you land directly on the project's overview page, instead of an empty dashboard asking you to create both by hand. Users joining from a team invite are added to their team's organization and skip the default workspace entirely, and provisioning happens exactly once — deleting the default org later never recreates it.
-
The project overview now shows a "Project setup" checklist while a project isn't fully wired up: add a source, add a destination, connect them, and send your first event. Steps check themselves off from the project's real state, the first incomplete step is highlighted, and the card disappears on its own when everything is done — or can be dismissed early per project.
-
When "Send your first event" becomes the checklist's active step, it shows your ingress URL ready to use: a copy-ready
curlcommand for public sources, or the URL with a paste-into-your-provider hint for sources that require authentication or restrict sender IPs. Only active sources are offered — a paused source's URL would reject the very delivery the step asks you to send. -
The MFA page no longer risks an endless reload when its return target points back at the MFA page itself — completing the challenge with such a target now lands on the dashboard, and an account with no enrolled authenticator sees an explanation instead of an endless spinner.
-
Creating a manual webhook source now shows the source's URL with a copy button on the confirmation screen — for every auth method — instead of telling you to go find it on the source's page.
-
Empty states now carry their own actions: the Sources and Destinations pages get an inline "Add" button (and the destinations empty state gains an icon and explanatory copy), the organizations list gets an inline "New Organization" button, and the overview's "no events yet" notice links to the Sources page.
-
Signing in, signing up, completing an MFA challenge, and setting a new password now perform a full page navigation into the dashboard, so everything on the first page — including the sidebar's organization list — always reflects the just-signed-in account. Signing out (and deleting an account) does the same in reverse, so the next page starts from a fully re-rendered, signed-out state.
-
Fixed a crash that could take down any dashboard page when a password manager or browser autofill dispatched a synthetic keyboard event — keyboard shortcuts now ignore events that carry no key.
-
Pausing or unlinking a source → destination link, or attaching a template, transform, or filter to one, now reports a clear error when the link no longer exists or you don't have permission to change it, instead of reporting success.
Dispatch now publishes a changelog at dispatch.tech/changelog. Every production release appears with its user-facing notes — new features, fixes, and behavior changes across the dashboard and API — grouped by release date, with an RSS feed to follow along. A "What's new" link in the dashboard sidebar takes you there.
Fixed creating a public (unauthenticated) source failing with a validation error. Source edits denied by your role's permissions now report an error instead of appearing to succeed.
- Connecting a Linear team, a Shopify store, or a Supabase table now stores the source's signing secret encrypted, matching every other integration.
- Setting a signing secret on a Twitch, YouTube, Salesforce, or PostHog source no longer breaks that integration's automatic provider-side renewal.
- When creating a GitHub, GitLab, or Bitbucket source fails, the error shown is the original failure — previously a cleanup failure could replace it with a generic message.
- Connecting an integration with a very long name (for example a deeply nested GitLab project path or a long Confluence space name) no longer fails source creation, and newly connected sources save correctly from the edit dialog — generated source names are truncated to fit the limit.
- Switching a source's authentication method, archiving, restoring, or deleting a source now reports an error when the change did not actually apply (for example the source was deleted concurrently) instead of reporting success, and shows a readable message rather than a raw database error.
- Connecting a PostHog project or a Salesforce org no longer includes the source's stored secret material in the browser response — Salesforce still shows the one-time signing secret needed for the Apex snippet. Both connect requests now validate their inputs with a clear error naming the failing field, instead of a generic failure. PostHog connect and event-type edit requests also ignore duplicate event types instead of creating duplicate PostHog functions that could never be cleaned up, and a failed event-type edit now cleans up the PostHog functions it had already created instead of leaving them orphaned.
- Connecting a PostHog project or a Salesforce org, editing a PostHog source's event types, or rotating its signing secret now requires a developer or admin role; event-type edits and secret rotations also validate their input with a clear error naming the failing field — previously a viewer's edit or rotation reported success while nothing saved (for rotation, leaving the source's deliveries failing). A successful rotation now always takes effect for delivery verification.
API v0.3.0
-
Routing rules on a source-destination link accept an optional
label— a short name for the rule, carried through unchanged and never used when deciding whether a rule matches. Rules saved without one are unaffected. -
Routing rules can now be tested against a sample event before they are saved. Submit a payload, optional headers and an ordered rule set, and the response reports which rule wins, what configuration it applies, and whether it suppresses delivery — evaluated by the same engine that routes real deliveries. Nothing is stored and no delivery is attempted.
-
Every rule and condition comes back with its own verdict, including the value found at each field path, so it is clear why a rule did or did not match. Rules that were never reached because an earlier rule already won, and rules that can never match because they have no conditions, are called out as such. The never-matches callout is a structured warning — it carries the index of the rule it belongs to and a stable code alongside its message — so a client can tie it to a rule row without parsing prose.
-
Invalid regular expressions are now reported instead of silently never matching. Routing patterns use Go's RE2 syntax, which a browser cannot check, and a pattern that fails to compile previously just made its condition false at delivery time. Unknown operators, field paths that name neither the body nor a header, and rules pointing at a reusable filter that no longer exists are reported the same way — each pinned to the rule and condition it came from and carrying a stable code, with the rest of the rule set still evaluated normally.
-
Each API instance evaluates at most 8 dry-runs at a time, so test traffic cannot monopolize the API's CPU. Requests beyond that answer
429 Too Many Requestswith aRetry-Afterheader — retry after a moment.
Routing rules now apply the per-rule Discord thread override to deliveries. A rule that set "post to thread" was previously accepted and saved but ignored at delivery time, so matching events went to the destination's default thread instead.
- Creating a source with an
oauth_connection_idthat doesn't exist now returns 400 with a clear error instead of 500. - Source slugs generated from very long names are now capped at 200 characters, the same limit enforced on caller-supplied slugs.
- All string fields on source creation and update — including the signing secret, on every route that accepts one — are now length-capped; an oversized value returns 400 with an error naming the field and its limit. Destination outbound signing secrets are capped the same way on create and rotation.
- Newly created public (unauthenticated) sources receive a fully opaque generated URL slug that no longer embeds the source's name — the URL is the source's only credential and is pasted into third-party services. Existing public sources, and sources switched to public later, keep their original slug so live senders aren't broken.