Skip to main content

Local Development with the Dispatch CLI

The dispatch CLI lets you forward incoming webhook events to a server running on your local machine. This means you can receive real webhooks from GitHub, Stripe, or any other service without exposing a public URL — perfect for local development and testing.

How It Works​

When dispatch listen is running, events arriving at your Dispatch endpoint are forwarded over a secure tunnel to http://localhost:<port>. Your local server handles the request and returns a response. The response is recorded and visible in the Events tab of the dashboard, giving you a full audit trail even during local development.

Events are only forwarded while the CLI is connected. Events that arrive when the CLI is not running are not buffered — reconnecting starts forwarding new events from that point onward.

Installation​

npm install -g @dispatch.tech/cli

PowerShell users should quote scoped package names:

npm install -g "@dispatch.tech/cli"

Requires Node.js 18 or later. Pre-compiled binaries for Linux, macOS, and Windows are downloaded automatically — no Go toolchain needed.

Via Go​

go install github.com/dispatch-services/dispatch/packages/cli/cmd/dispatch@latest

Ensure $GOPATH/bin is on your PATH.

Authenticate​

dispatch login

An interactive picker lets you choose how to sign in:

Select a login method:
► Email and password
Continue with GitHub (opens browser)
Continue with Google (opens browser)

To skip the picker and go straight to a browser-based flow, pass --provider:

dispatch login --provider github
dispatch login --provider google

Only session tokens are saved to ~/.dispatch/config.yaml (file permissions 0600). Passwords and OAuth secrets are never stored. If DISPATCH_ACCESS_TOKEN / DISPATCH_REFRESH_TOKEN are set, they override the saved login on every command — login warns when that's the case; unset them to use the fresh session. It also warns when a project-local .dispatch.yaml still holds credentials, since that file outranks the global login.

Log Out​

dispatch logout

Clears stored credentials from ~/.dispatch/config.yaml. Run dispatch login again to re-authenticate. Credentials supplied via DISPATCH_ACCESS_TOKEN / DISPATCH_REFRESH_TOKEN live in your environment, not in the file — logout warns when they're set, and unsetting them is what signs those sessions out. It also warns whenever a walked-up project .dispatch.yaml still holds credentials — even from dispatch logout --local in a subdirectory — clear that file with dispatch logout --local from its own directory.

Start Listening​

dispatch listen 3000

Run at a terminal, an interactive picker lets you choose your organization, project, and webhook source (headless runs skip the picker — see below). Once connected, the terminal shows a live stream of forwarded events:

  Listening on  my-github-source → localhost:3000/

Connected.

→ POST push 200 42ms
→ POST pull_request 200 11ms

Specify a source directly​

dispatch listen 3000 my-github-source

Forward to a specific path​

dispatch listen 3000 my-github-source --path /api/webhooks

Events are POSTed to http://localhost:3000/api/webhooks.

Skip the org, project, and source pickers​

dispatch listen 3000 my-source-slug --project proj_abc123

Pre-answer the option pickers​

Each optional picker can be answered from the command line, so any step you cover with a flag never prompts:

dispatch listen 3000 my-source-slug --project proj_abc123 --transform normalize --delay 0

--filter, --transform, and --template take a resource name (matched case-insensitively) or id, or none to explicitly pick nothing — none is reserved, so a resource actually named "None" must be selected by its id. --delay takes seconds.

Headless / CI mode​

Pass --no-interactive — or just run with stdin not attached to a terminal (CI, pipes), which enables it automatically — and listen never prompts: unanswered optional pickers default to none / no delay, and a choice that would have required a picker (like an ambiguous source) errors with the available options listed instead. Authentication can come entirely from the environment via DISPATCH_ACCESS_TOKEN and DISPATCH_REFRESH_TOKEN, so a CI job never needs dispatch login or a config file:

export DISPATCH_ACCESS_TOKEN="<access token>"
export DISPATCH_REFRESH_TOKEN="<refresh token>"
dispatch listen 3000 my-source-slug --project proj_abc123

In-session keyboard shortcuts are disabled in headless runs; stop the process with SIGINT/SIGTERM.

Keyboard Shortcuts While Listening​

KeyAction
rReplay the last received event
pPause / resume forwarding
cChange source, filter, transform, template, or delay
hPrint keyboard shortcut help
q / Ctrl+CExit

Interactive Picker​

The picker walks through org → project → source. Press Esc or Backspace to go back one level. If you have only one org and one project, those steps are skipped automatically.

After selecting a source, you are offered optional settings:

  • Filter — apply a named filter to only forward events that match its conditions
  • Transform — apply a named JSONata transform to the payload before it is forwarded
  • Template — apply a message template
  • Delivery delay — introduce a deliberate delay before forwarding (useful for testing timeout handling)

CLI Destination in the Dashboard​

Every dispatch listen session creates (or reuses) a CLI destination in your project. It appears on the Destinations page as:

CLI · alice@my-laptop

This is how Dispatch knows where to forward events. You can safely ignore or delete these destinations — the CLI recreates them automatically on next run.

Configuration File​

The CLI stores its state in ~/.dispatch/config.yaml. You can run dispatch config to see which files are active and which URLs are in use:

dispatch config

Per-project credentials​

If you work across multiple accounts or want to commit a project-specific API URL, you can log in with --local:

dispatch login --local

This saves credentials to .dispatch.yaml in the current directory instead of the global config. Make sure to add .dispatch.yaml to your .gitignore.

Per-project credentials take precedence over the global config.

Check Your Version​

dispatch version

Common Error Messages​

MessageWhat to do
not logged in — run 'dispatch login' firstRun dispatch login.
invalid port: <value>Use a number between 1 and 65535.
could not reach Dispatch API at <url>Check your network connection.
no sources foundCreate a webhook source in the dashboard first.
refresh failedYour session expired — run dispatch login again.