{"id":13513931,"url":"https://github.com/hookdeck/hookdeck-cli","last_synced_at":"2026-03-12T15:07:00.304Z","repository":{"id":38302462,"uuid":"346862690","full_name":"hookdeck/hookdeck-cli","owner":"hookdeck","description":"Alternative to ngrok for localhost asynchronous web development (e.g. webhooks). No account required.","archived":false,"fork":false,"pushed_at":"2026-03-06T16:14:51.000Z","size":7597,"stargazers_count":349,"open_issues_count":26,"forks_count":15,"subscribers_count":7,"default_branch":"main","last_synced_at":"2026-03-06T16:55:51.840Z","etag":null,"topics":["cli","hookdeck","localtunnel","ngrok-alternative","webhooks"],"latest_commit_sha":null,"homepage":"https://hookdeck.com?ref=github-hookdeck-cli","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hookdeck.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2021-03-11T22:56:39.000Z","updated_at":"2026-03-05T15:57:39.000Z","dependencies_parsed_at":"2023-11-19T21:27:50.271Z","dependency_job_id":"c083778d-aad5-4ff3-86ea-7b8d8c5c3e8a","html_url":"https://github.com/hookdeck/hookdeck-cli","commit_stats":{"total_commits":194,"total_committers":12,"mean_commits":"16.166666666666668","dds":0.7216494845360825,"last_synced_commit":"7d33389130a4a0d8a27f298460ccdab0967ec944"},"previous_names":[],"tags_count":77,"template":false,"template_full_name":null,"purl":"pkg:github/hookdeck/hookdeck-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hookdeck","download_url":"https://codeload.github.com/hookdeck/hookdeck-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hookdeck%2Fhookdeck-cli/sbom","scorecard":{"id":468903,"data":{"date":"2025-08-11","repo":{"name":"github.com/hookdeck/hookdeck-cli","commit":"c444291e47da5f6422a150b857af3ca29db5801d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.8,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 3 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/9 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/acceptance-test.yml:1","Warn: no topLevel permission defined: .github/workflows/dependabot_pr.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Warn: no topLevel permission defined: .github/workflows/test.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v1.0.3 not signed: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/239119541","Warn: release artifact v1.0.2 not signed: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/238580186","Warn: release artifact v1.0.1 not signed: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/237579471","Warn: release artifact v1.0.0-beta.3 not signed: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/225552143","Warn: release artifact v1.0.0-beta.2 not signed: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/225542514","Warn: release artifact v1.0.3 does not have provenance: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/239119541","Warn: release artifact v1.0.2 does not have provenance: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/238580186","Warn: release artifact v1.0.1 does not have provenance: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/237579471","Warn: release artifact v1.0.0-beta.3 does not have provenance: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/225552143","Warn: release artifact v1.0.0-beta.2 does not have provenance: https://api.github.com/repos/hookdeck/hookdeck-cli/releases/225542514"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/acceptance-test.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/acceptance-test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/acceptance-test.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/acceptance-test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:82: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:107: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:121: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:128: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:35: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:44: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:46: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:48: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:63: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:71: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:41: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:45: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:50: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:54: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:58: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:69: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:73: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:77: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/test.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/test.yml:26: update your workflow using https://app.stepsecurity.io/secureworkflow/hookdeck/hookdeck-cli/test.yml/main?enable=pin","Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating alpine to alpine@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1","Info:   0 out of  16 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of  14 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release.yml:78"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"10 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0968 / GHSA-gwc9-m7rh-j2ww","Warn: Project is vulnerable to: GO-2021-0356 / GHSA-8c26-wmh5-6g9v","Warn: Project is vulnerable to: GO-2024-2961","Warn: Project is vulnerable to: GO-2023-2402 / GHSA-45x7-px36-x8w8","Warn: Project is vulnerable to: GO-2024-3321 / GHSA-v778-237x-gjrc","Warn: Project is vulnerable to: GO-2025-3487 / GHSA-hcg3-q754-cr77","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T13:16:03.943Z","repository_id":38302462,"created_at":"2025-08-19T13:16:03.943Z","updated_at":"2025-08-19T13:16:03.943Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30314593,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-09T20:05:46.299Z","status":"ssl_error","status_checked_at":"2026-03-09T19:57:04.425Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","hookdeck","localtunnel","ngrok-alternative","webhooks"],"created_at":"2024-08-01T05:00:40.521Z","updated_at":"2026-03-09T22:07:35.609Z","avatar_url":"https://github.com/hookdeck.png","language":"Go","readme":"# Hookdeck CLI\n\n[slack-badge]: https://img.shields.io/badge/Slack-Hookdeck%20Developers-blue?logo=slack\n\n[![slack-badge]](https://join.slack.com/t/hookdeckdevelopers/shared_invite/zt-yw7hlyzp-EQuO3QvdiBlH9Tz2KZg5MQ)\n\nUsing the Hookdeck CLI, you can forward your events (e.g. webhooks) to your local web server with unlimited **free** and **permanent** event URLs. Your event history is preserved between sessions and can be viewed, replayed, or used for testing by you and your teammates.\n\nHookdeck CLI is compatible with most of Hookdeck's features, such as filtering and fan-out delivery. You can use Hookdeck CLI to develop or test your event (e.g. webhook) integration code locally.\n\nAlthough it uses a different approach and philosophy, it's a replacement for ngrok and alternative HTTP tunnel solutions.\n\nHookdeck for development is completely free, and we monetize the platform with our production offering.\n\nFor a complete reference of all commands and flags, see [REFERENCE.md](REFERENCE.md).\n\nhttps://github.com/user-attachments/assets/7a333c5b-e4cb-45bb-8570-29fafd137bd2\n\n\n## Installation\n\nHookdeck CLI is available for macOS, Windows, and Linux for distros like Ubuntu, Debian, RedHat, and CentOS.\n\n### NPM\n\nHookdeck CLI is distributed as an NPM package:\n\n```sh\nnpm install hookdeck-cli -g\n```\n\nTo install a beta (pre-release) version:\n\n```sh\nnpm install hookdeck-cli@beta -g\n```\n\n### macOS\n\nHookdeck CLI is available on macOS via [Homebrew](https://brew.sh/):\n\n```sh\nbrew install hookdeck/hookdeck/hookdeck\n```\n\nTo install a beta (pre-release) version:\n\n```sh\nbrew install hookdeck/hookdeck/hookdeck-beta\n```\n\n### Windows\n\nHookdeck CLI is available on Windows via the [Scoop](https://scoop.sh/) package manager:\n\n```sh\nscoop bucket add hookdeck https://github.com/hookdeck/scoop-hookdeck-cli.git\nscoop install hookdeck\n```\n\nTo install a beta (pre-release) version:\n\n```sh\nscoop install hookdeck-beta\n```\n\n### Linux Or without package managers\n\nTo install the Hookdeck CLI on Linux without a package manager:\n\n1. Download the latest linux tar.gz file from https://github.com/hookdeck/hookdeck-cli/releases/latest\n2. Unzip the file: tar -xvf hookdeck_X.X.X_linux_amd64.tar.gz\n3. Run the executable: ./hookdeck\n\nFor beta (pre-release) versions, download the `.deb` or `.rpm` packages from the [GitHub releases page](https://github.com/hookdeck/hookdeck-cli/releases) (look for releases marked as \"Pre-release\").\n\n### Docker\n\nThe CLI is also available as a Docker image: [`hookdeck/hookdeck-cli`](https://hub.docker.com/r/hookdeck/hookdeck-cli).\n\n```sh\ndocker run --rm -it hookdeck/hookdeck-cli version\nhookdeck version x.y.z (beta)\n```\n\nTo use a specific version (including beta releases), specify the version tag:\n\n```sh\ndocker run --rm -it hookdeck/hookdeck-cli:v1.2.3-beta.1 version\n```\n\nNote: Beta releases do not update the `latest` tag. Only stable releases update `latest`.\n\nIf you want to login to your Hookdeck account with the CLI and persist\ncredentials, you can bind mount the `~/.config/hookdeck` directory:\n\n```sh\ndocker run --rm -it -v $HOME/.config/hookdeck:/root/.config/hookdeck hookdeck/hookdeck-cli login\n```\n\nThen you can listen on any of your sources. Don't forget to use\n`host.docker.internal` to reach a port on your host machine, otherwise\nthat port will not be accessible from `localhost` inside the container.\n\n```sh\ndocker run --rm -it -v $HOME/.config/hookdeck:/root/.config/hookdeck hookdeck/hookdeck-cli listen http://host.docker.internal:1234\n```\n\n## Usage\n\nInstalling the CLI provides access to the `hookdeck` command.\n\n```sh\nhookdeck [command]\n\n# Run `--help` for detailed information about CLI commands\nhookdeck [command] help\n```\n\n## Commands\n\n### Login\n\nLogin with your Hookdeck account. This will typically open a browser window for authentication.\n\n```sh\nhookdeck login\n```\n\nIf you are in an environment without a browser (e.g., a TTY-only terminal), you can use the `--interactive` (or `-i`) flag to log in by pasting your API key:\n\n```sh\nhookdeck login --interactive\n```\n\n\u003e Login is optional, if you do not login a temporary guest account will be created for you when you run other commands.\n\n### Listen\n\nStart a session to forward your events to an HTTP server.\n\n```sh\nhookdeck listen \u003cport-or-URL\u003e \u003csource-alias?\u003e \u003cconnection-query?\u003e [flags]\n\nFlags:\n  --path string             Sets the path to which events are forwarded (e.g., /webhooks or /api/stripe)\n  --output string           Output mode: interactive (full UI), compact (simple logs), quiet (only fatal errors) (default \"interactive\")\n  --max-connections int     Maximum concurrent connections to local endpoint (default: 50, increase for high-volume testing)\n  --filter-body string      Filter events by request body using Hookdeck filter syntax (JSON)\n  --filter-headers string   Filter events by request headers using Hookdeck filter syntax (JSON)\n  --filter-query string     Filter events by query parameters using Hookdeck filter syntax (JSON)\n  --filter-path string      Filter events by request path using Hookdeck filter syntax (JSON)\n```\n\nHookdeck works by routing events received for a given `source` (i.e., Shopify, Github, etc.) to its defined `destination` by connecting them with a `connection` to a `destination`. The CLI allows you to receive events for any given connection and forward them to your localhost at the specified port or any valid URL.\n\nEach `source` is assigned an Event URL, which you can use to receive events. When starting with a fresh account, the CLI will prompt you to create your first source. Each CLI process can listen to one source at a time.\n\n\u003e The `port-or-URL` param is mandatory, events will be forwarded to http://localhost:$PORT/$DESTINATION_PATH when inputing a valid port or your provided URL.\n\n#### Interactive Mode\n\nThe default interactive mode uses a full-screen TUI (Terminal User Interface) with an alternative screen buffer, meaning your terminal history is preserved when you exit. The interface includes:\n\n- **Connection Header**: Shows your sources, webhook URLs, and connection routing\n  - Auto-collapses when the first event arrives to save space\n  - Toggle with `i` to expand/collapse connection details\n- **Event List**: Scrollable history of all received events (up to 1000 events)\n  - Auto-scrolls to show latest events as they arrive\n  - Manual navigation pauses auto-scrolling\n- **Status Bar**: Shows event details and available keyboard shortcuts\n- **Event Details View**: Full request/response inspection with headers and body\n\n#### Interactive Keyboard Shortcuts\n\nWhile in interactive mode, you can use the following keyboard shortcuts:\n\n- `↑` / `↓` or `k` / `j` - Navigate between events (select different events)\n- `i` - Toggle connection information (expand/collapse connection details)\n- `r` - Retry the selected event\n- `o` - Open the selected event in the Hookdeck dashboard\n- `d` - Show detailed request/response information for the selected event (press `d` or `ESC` to close)\n  - When details view is open: `↑` / `↓` scroll through content, `PgUp` / `PgDown` for page navigation\n- `q` - Quit the application (terminal state is restored)\n- `Ctrl+C` - Also quits the application\n\nThe selected event is indicated by a `\u003e` character at the beginning of the line. All actions (retry, open, details) work on the currently selected event, not just the latest one. These shortcuts are displayed in the status bar at the bottom of the screen.\n\n#### Listen to all your connections for a given source\n\nThe second param, `source-alias` is used to select a specific source to listen on. By default, the CLI will start listening on all eligible connections for that source.\n\n```sh\n$ hookdeck listen 3000 shopify\n\n●── HOOKDECK CLI ──●\n\nListening on 1 source • 2 connections • [i] Collapse\n\nShopify Source\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHnOH\n├─ Forwards to → http://localhost:3000/webhooks/shopify/inventory (Inventory Service)\n└─ Forwards to → http://localhost:3000/webhooks/shopify/orders (Orders Service)\n\n💡 Open dashboard to inspect, retry \u0026 bookmark events: https://dashboard.hookdeck.com/events/cli?team_id=...\n\nEvents • [↑↓] Navigate ──────────────────────────────────────────────────────────\n\n2025-10-12 14:32:15 [200] POST http://localhost:3000/webhooks/shopify/orders (23ms) → https://dashboard.hookdeck.com/events/evt_...\n\u003e 2025-10-12 14:32:18 [200] POST http://localhost:3000/webhooks/shopify/inventory (45ms) → https://dashboard.hookdeck.com/events/evt_...\n\n───────────────────────────────────────────────────────────────────────────────\n\u003e ✓ Last event succeeded with status 200 | [r] Retry • [o] Open in dashboard • [d] Show data\n```\n\n#### Listen to multiple sources\n\n`source-alias` can be a comma-separated list of source names (for example, `stripe,shopify,twilio`) or `'*'` (with quotes) to listen to all sources.\n\n```sh\n$ hookdeck listen 3000 '*'\n\n●── HOOKDECK CLI ──●\n\nListening on 3 sources • 3 connections • [i] Collapse\n\nstripe\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHn01\n└─ Forwards to → http://localhost:3000/webhooks/stripe (cli-stripe)\n\nshopify\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHn02\n└─ Forwards to → http://localhost:3000/webhooks/shopify (cli-shopify)\n\ntwilio\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHn03\n└─ Forwards to → http://localhost:3000/webhooks/twilio (cli-twilio)\n\n💡 Open dashboard to inspect, retry \u0026 bookmark events: https://dashboard.hookdeck.com/events/cli?team_id=...\n\nEvents • [↑↓] Navigate ──────────────────────────────────────────────────────────\n\n2025-10-12 14:35:21 [200] POST http://localhost:3000/webhooks/stripe (12ms) → https://dashboard.hookdeck.com/events/evt_...\n2025-10-12 14:35:44 [200] POST http://localhost:3000/webhooks/shopify (31ms) → https://dashboard.hookdeck.com/events/evt_...\n\u003e 2025-10-12 14:35:52 [200] POST http://localhost:3000/webhooks/twilio (18ms) → https://dashboard.hookdeck.com/events/evt_...\n\n───────────────────────────────────────────────────────────────────────────────\n\u003e ✓ Last event succeeded with status 200 | [r] Retry • [o] Open in dashboard • [d] Show data\n```\n\n#### Listen to a subset of connections\n\nThe 3rd param, `connection-query` specifies which connection with a CLI destination to adopt for listening. By default, the first connection with a CLI destination type will be used. If a connection with the specified name doesn't exist, a new connection will be created with the passed value. The connection query is checked against the `connection` name, `alias`, and the `path` values.\n\n```sh\n$ hookdeck listen 3000 shopify orders\n\n●── HOOKDECK CLI ──●\n\nListening on 1 source • 1 connection • [i] Collapse\n\nShopify Source\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHnOH\n└─ Forwards to → http://localhost:3000/webhooks/shopify/orders (Orders Service)\n\n💡 Open dashboard to inspect, retry \u0026 bookmark events: https://dashboard.hookdeck.com/events/cli?team_id=...\n\nEvents • [↑↓] Navigate ──────────────────────────────────────────────────────────\n\n\u003e 2025-10-12 14:38:09 [200] POST http://localhost:3000/webhooks/shopify/orders (27ms) → https://dashboard.hookdeck.com/events/evt_...\n\n───────────────────────────────────────────────────────────────────────────────\n\u003e ✓ Last event succeeded with status 200 | [r] Retry • [o] Open in dashboard • [d] Show data\n```\n\n#### Changing the path events are forwarded to\n\nThe `--path` flag sets the path to which events are forwarded.\n\n```sh\n$ hookdeck listen 3000 shopify orders --path /events/shopify/orders\n\n●── HOOKDECK CLI ──●\n\nListening on 1 source • 1 connection • [i] Collapse\n\nShopify Source\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHnOH\n└─ Forwards to → http://localhost:3000/events/shopify/orders (Orders Service)\n\n💡 Open dashboard to inspect, retry \u0026 bookmark events: https://dashboard.hookdeck.com/events/cli?team_id=...\n\nEvents • [↑↓] Navigate ──────────────────────────────────────────────────────────\n\n\u003e 2025-10-12 14:40:23 [200] POST http://localhost:3000/events/shopify/orders (19ms) → https://dashboard.hookdeck.com/events/evt_...\n\n───────────────────────────────────────────────────────────────────────────────\n\u003e ✓ Last event succeeded with status 200 | [r] Retry • [o] Open in dashboard • [d] Show data\n```\n\n#### Controlling output verbosity\n\nThe `--output` flag controls how events are displayed. This is useful for reducing resource usage in high-throughput scenarios or when running in the background.\n\n**Available modes:**\n\n- `interactive` (default) - Full-screen TUI with alternative screen buffer, event history, navigation, and keyboard shortcuts. Your terminal history is preserved and restored when you exit.\n- `compact` - Simple one-line logs for all events without interactive features. Events are appended to your terminal history.\n- `quiet` - Only displays fatal connection errors (network failures, timeouts), not HTTP errors\n\nAll modes display connection information at startup and a connection status message.\n\n**Examples:**\n\n```sh\n# Default - full interactive UI with keyboard shortcuts\n$ hookdeck listen 3000 shopify\n\n# Simple logging mode - prints all events as one-line logs\n$ hookdeck listen 3000 shopify --output compact\n\n# Quiet mode - only shows fatal connection errors\n$ hookdeck listen 3000 shopify --output quiet\n```\n\n**Compact mode output:**\n\n```\nListening on\nshopify\n└─ Forwards to → http://localhost:3000\n\nConnected. Waiting for events...\n\n2025-10-08 15:56:53 [200] POST http://localhost:3000 (45ms) → https://...\n2025-10-08 15:56:54 [422] POST http://localhost:3000 (12ms) → https://...\n```\n\n**Quiet mode output:**\n\n```\nListening on\nshopify\n└─ Forwards to → http://localhost:3000\n\nConnected. Waiting for events...\n\n2025-10-08 15:56:53 [ERROR] Failed to POST: connection refused\n```\n\n\u003e Note: In `quiet` mode, only fatal errors are shown (connection failures, network unreachable, timeouts). HTTP error responses (4xx, 5xx) are not displayed as they are valid HTTP responses.\n\n#### Filtering events\n\nThe CLI supports filtering events using Hookdeck's filter syntax. Filters allow you to receive only events that match specific conditions, reducing noise and focusing on the events you care about during development.\n\n**Filter flags:**\n\n- `--filter-body` - Filter events by request body content (JSON)\n- `--filter-headers` - Filter events by request headers (JSON)\n- `--filter-query` - Filter events by query parameters (JSON)\n- `--filter-path` - Filter events by request path (JSON)\n\nAll filter flags accept JSON using [Hookdeck's filter syntax](https://hookdeck.com/docs/filters). You can use exact matches or operators like `$exist`, `$gte`, `$lte`, `$in`, etc.\n\n**Examples:**\n\n```sh\n# Filter events by body content (only events with matching data)\nhookdeck listen 3000 github --filter-body '{\"action\": \"opened\"}'\n\n# Filter events with multiple conditions\nhookdeck listen 3000 stripe --filter-body '{\"type\": \"charge.succeeded\"}' --filter-headers '{\"x-stripe-signature\": {\"$exist\": true}}'\n\n# Filter using operators\nhookdeck listen 3000 api --filter-body '{\"amount\": {\"$gte\": 100}}'\n```\n\nWhen filters are active, the CLI will display a warning message indicating which filters are applied. Only events matching all specified filter conditions will be forwarded to your local server.\n\n#### Viewing and interacting with your events\n\nEvent logs for your CLI can be found at [https://dashboard.hookdeck.com/cli/events](https://dashboard.hookdeck.com/cli/events?ref=github-hookdeck-cli). Events can be replayed or saved at any time.\n\n### Logout\n\nLogout of your Hookdeck account and clear your stored credentials.\n\n```sh\nhookdeck logout\n```\n\n### Skip SSL validation\n\nWhen forwarding events to an HTTPS URL as the first argument to `hookdeck listen` (e.g., `https://localhost:1234/webhook`), you might encounter SSL validation errors if the destination is using a self-signed certificate.\n\nFor local development scenarios, you can instruct the `listen` command to bypass this SSL certificate validation by using its `--insecure` flag. You must provide the full HTTPS URL. This flag also applies to the periodic server health checks that the CLI performs.\n\n**This is dangerous and should only be used in trusted local development environments for destinations you control.**\n\nExample of skipping SSL validation for an HTTPS destination:\n\n```sh\nhookdeck listen --insecure https://\u003cyour-ssl-url-or-url:port\u003e/ \u003csource-alias?\u003e \u003cconnection-query?\u003e\n```\n\n### Disable health checks\n\nThe CLI periodically checks if your local server is reachable and displays warnings if the connection fails. If these health checks cause issues in your environment, you can disable them with the `--no-healthcheck` flag:\n\n```sh\nhookdeck listen --no-healthcheck 3000 \u003csource-alias?\u003e\n```\n\n### Version\n\nPrint your CLI version and whether or not a new version is available.\n\n```sh\nhookdeck version\n```\n\n### Completion\n\nConfigure auto-completion for Hookdeck CLI. It is run on install when using Homebrew or Scoop. You can optionally run this command when using the binaries directly or without a package manager.\n\n```sh\nhookdeck completion\n```\n\n### Running in CI\n\nIf you want to use Hookdeck in CI for tests or any other purposes, you can use your HOOKDECK_API_KEY to authenticate and start forwarding events.\n\n```sh\n$ hookdeck ci --api-key $HOOKDECK_API_KEY\nDone! The Hookdeck CLI is configured in project MyProject\n\n$ hookdeck listen 3000 shopify orders\n\n●── HOOKDECK CLI ──●\n\nListening on 1 source • 1 connection • [i] Collapse\n\nShopify Source\n│  Requests to → https://events.hookdeck.com/e/src_DAjaFWyyZXsFdZrTOKpuHnOH\n└─ Forwards to → http://localhost:3000/webhooks/shopify/orders (Orders Service)\n\n💡 Open dashboard to inspect, retry \u0026 bookmark events: https://dashboard.hookdeck.com/events/cli?team_id=...\n\nEvents • [↑↓] Navigate ──────────────────────────────────────────────────────────\n\n\u003e 2025-10-12 14:42:55 [200] POST http://localhost:3000/webhooks/shopify/orders (34ms) → https://dashboard.hookdeck.com/events/evt_...\n\n───────────────────────────────────────────────────────────────────────────────\n\u003e ✓ Last event succeeded with status 200 | [r] Retry • [o] Open in dashboard • [d] Show data\n```\n\n### Event Gateway\n\nThe `hookdeck gateway` command provides full access to Hookdeck Event Gateway resources. Use these subcommands to manage infrastructure and inspect events:\n\n| Command group | Description |\n|---------------|-------------|\n| `hookdeck gateway connection` | Create and manage connections between sources and destinations |\n| `hookdeck gateway source` | Manage inbound webhook sources |\n| `hookdeck gateway destination` | Manage destinations (HTTP endpoints, CLI, etc.) |\n| `hookdeck gateway event` | List, get, retry, cancel, or mute events (processed deliveries) |\n| `hookdeck gateway request` | List, get, and retry requests (raw inbound webhooks) |\n| `hookdeck gateway attempt` | List and get delivery attempts |\n| `hookdeck gateway transformation` | Create and manage JavaScript transformations |\n\n**Examples:**\n\n```sh\n# List sources and destinations\nhookdeck gateway source list\nhookdeck gateway destination list\n\n# List events (processed deliveries) and requests (raw inbound webhooks)\nhookdeck gateway event list --status FAILED\nhookdeck gateway request list --source-id src_abc123\n\n# List attempts for an event\nhookdeck gateway attempt list --event-id evt_abc123\n\n# Create a transformation and test-run it\nhookdeck gateway transformation create --name my-transform --code \"addHandler(\\\"transform\\\", (request, context) =\u003e { return request; });\"\nhookdeck gateway transformation run --code \"addHandler(\\\"transform\\\", (request, context) =\u003e { return request; });\" --request '{\"headers\":{}}'\n```\n\nFor complete command and flag reference, see [REFERENCE.md](REFERENCE.md).\n\n### Manage connections\n\nCreate and manage webhook connections between sources and destinations with inline resource creation, authentication, processing rules, and lifecycle management. Use `hookdeck gateway connection` (or the backward-compatible alias `hookdeck connection`). For detailed examples with authentication, filters, retry rules, and rate limiting, see the complete [connection management](#manage-connections) section below.\n\n```sh\nhookdeck gateway connection [command]\n\n# Available commands\nhookdeck gateway connection list      # List all connections\nhookdeck gateway connection get       # Get connection details\nhookdeck gateway connection create    # Create a new connection\nhookdeck gateway connection upsert    # Create or update a connection (idempotent)\nhookdeck gateway connection update    # Update a connection\nhookdeck gateway connection delete    # Delete a connection\nhookdeck gateway connection enable    # Enable a connection\nhookdeck gateway connection disable   # Disable a connection\nhookdeck gateway connection pause     # Pause a connection\nhookdeck gateway connection unpause   # Unpause a connection\n```\n\n#### Sources and destinations\n\nYou can manage sources and destinations independently, not only inline when creating connections. Create reusable sources (e.g. Stripe, GitHub) and destinations (HTTP endpoints) that multiple connections can reference.\n\n```sh\n# List and inspect sources and destinations\nhookdeck gateway source list\nhookdeck gateway source get src_abc123\n\nhookdeck gateway destination list\nhookdeck gateway destination get dst_abc123\n\n# Create a standalone destination\nhookdeck gateway destination create --name \"my-api\" --type HTTP --url \"https://api.example.com/webhooks\"\n```\n\nSee [Sources](REFERENCE.md#sources) and [Destinations](REFERENCE.md#destinations) in REFERENCE.md.\n\n### Transformations\n\nTransformations are JavaScript modules that modify requests before delivery. They are attached to connections and can add headers, transform the body, or filter events. Create, test, and manage transformations with `hookdeck gateway transformation`:\n\n```sh\n# Create a transformation\nhookdeck gateway transformation create --name my-transform --code \"addHandler(\\\"transform\\\", (request, context) =\u003e { return request; });\"\n\n# Test run transformation code (see transformed output)\nhookdeck gateway transformation run --code \"addHandler(\\\"transform\\\", (request, context) =\u003e { return request; });\" --request '{\"headers\":{}}'\n\n# List and use with connections (--transformation-name when creating connections)\nhookdeck gateway transformation list\n```\n\nSee [Transformations](REFERENCE.md#transformations) in REFERENCE.md.\n\n### Requests, events, and attempts\n\nWebhooks flow through Hookdeck as **requests** (raw inbound), then **events** (processed, routed), then **attempts** (delivery tries). Use these commands to inspect, filter, and retry:\n\n```sh\n# List requests (raw inbound webhooks) and filter by source\nhookdeck gateway request list --source-id src_abc123\nhookdeck gateway request get req_abc123\n\n# List events (processed deliveries) by status\nhookdeck gateway event list --status FAILED\nhookdeck gateway event list --status PENDING\nhookdeck gateway event get evt_abc123\n\n# Retry a failed event or request\nhookdeck gateway event retry evt_abc123\nhookdeck gateway request retry req_abc123\n\n# List attempts (individual delivery tries) for an event\nhookdeck gateway attempt list --event-id evt_abc123\n```\n\nSee [Requests](REFERENCE.md#requests), [Events](REFERENCE.md#events), and [Attempts](REFERENCE.md#attempts) in REFERENCE.md.\n\n### Manage active project\n\nIf you are a part of multiple projects, you can switch between them using our project management commands.\n\n#### List projects\n\n```sh\n# List all projects\n$ hookdeck project list\nMy Org / My Project (current)\nMy Org / Another Project\nAnother Org / Yet Another One\n\n# Filter by organization and project name\n$ hookdeck project list Org Proj\nMy Org / My Project (current)\nMy Org / Another Project\n```\n\n#### Select active project\n\n```console\nhookdeck project use [\u003corganization_name\u003e [\u003cproject_name\u003e]] [--local]\n\nFlags:\n  --local    Save project to current directory (.hookdeck/config.toml)\n```\n\n**Project Selection Modes:**\n\n- **No arguments**: Interactive prompt to select organization and project\n- **One argument**: Filter by organization name (prompts if multiple projects)\n- **Two arguments**: Directly select organization and project\n\n```sh\n$ hookdeck project use my-org my-project\nSuccessfully set active project to: my-org / my-project\n```\n\n#### Configuration scope: Global vs Local\n\nBy default, `project use` saves your selection to the **global configuration** (`~/.config/hookdeck/config.toml`). You can pin a specific project to the **current directory** using the `--local` flag.\n\n**Configuration file precedence (only ONE is used):**\n\nThe CLI uses exactly one configuration file based on this precedence:\n\n1. **Custom config** (via `--config` flag) - highest priority\n2. **Local config** - `${PWD}/.hookdeck/config.toml` (if exists)\n3. **Global config** - `~/.config/hookdeck/config.toml` (default)\n\nUnlike Git, Hookdeck **does not merge** multiple config files - only the highest precedence config is used.\n\n**Examples:**\n\n```sh\n# No local config exists → saves to global\n$ hookdeck project use my-org my-project\nSuccessfully set active project to: my-org / my-project\nSaved to: ~/.config/hookdeck/config.toml\n\n# Local config exists → automatically updates local\n$ cd ~/repo-with-local-config  # has .hookdeck/config.toml\n$ hookdeck project use another-org another-project\nSuccessfully set active project to: another-org / another-project\nUpdated: .hookdeck/config.toml\n\n# Create new local config\n$ cd ~/my-new-repo  # no .hookdeck/ directory\n$ hookdeck project use my-org my-project --local\nSuccessfully set active project to: my-org / my-project\nCreated: .hookdeck/config.toml\n⚠️  Security: Add .hookdeck/ to .gitignore (contains credentials)\n\n# Update existing local config with confirmation\n$ hookdeck project use another-org another-project --local\nLocal configuration already exists at: .hookdeck/config.toml\n? Overwrite with new project configuration? (y/N) y\nSuccessfully set active project to: another-org / another-project\nUpdated: .hookdeck/config.toml\n```\n\n**Smart default behavior:**\n\nWhen you run `project use` without `--local`:\n- **If `.hookdeck/config.toml` exists**: Updates the local config\n- **Otherwise**: Updates the global config\n\nThis ensures your directory-specific configuration is preserved when it exists.\n\n**Flag validation:**\n\n```sh\n# ✅ Valid\nhookdeck project use my-org my-project\nhookdeck project use my-org my-project --local\n\n# ❌ Invalid (cannot combine --config with --local)\nhookdeck --config custom.toml project use my-org my-project --local\nError: --local and --config flags cannot be used together\n  --local creates config at: .hookdeck/config.toml\n  --config uses custom path: custom.toml\n```\n\n#### Benefits of local project pinning\n\n- **Per-repository configuration**: Each repository can use a different Hookdeck project\n- **Team collaboration**: Commit `.hookdeck/config.toml` to private repos (see security note)\n- **No context switching**: Automatically uses the right project when you `cd` into a directory\n- **CI/CD friendly**: Works seamlessly in automated environments\n\n#### Security: Config files and source control\n\n⚠️ **IMPORTANT**: Configuration files contain your Hookdeck credentials and should be treated as sensitive.\n\n**Credential Types:**\n\n- **CLI Key**: Created when you run `hookdeck login` (interactive authentication)\n- **CI Key**: Created in the Hookdeck dashboard for use in CI/CD pipelines\n- Both are stored as `api_key` in config files\n\n**Recommended practices:**\n\n- **Private repositories**: You MAY commit `.hookdeck/config.toml` if your repository is guaranteed to remain private and all collaborators should have access to the credentials.\n\n- **Public repositories**: You MUST add `.hookdeck/` to your `.gitignore`:\n  ```gitignore\n  # Hookdeck CLI configuration (contains credentials)\n  .hookdeck/\n  ```\n\n- **CI/CD environments**: Use the `HOOKDECK_API_KEY` environment variable:\n  ```sh\n  # The ci command automatically reads HOOKDECK_API_KEY\n  export HOOKDECK_API_KEY=\"your-ci-key\"\n  hookdeck ci\n  hookdeck listen 3000\n  ```\n\n**Checking which config is active:**\n\n```sh\n$ hookdeck whoami\nLogged in as: user@example.com\nActive project: my-org / my-project\nConfig file: /Users/username/my-repo/.hookdeck/config.toml (local)\n```\n\n**Removing local configuration:**\n\nTo stop using local configuration and switch back to global:\n\n```sh\n$ rm -rf .hookdeck/\n# Now CLI uses global config\n```\n\n### Manage connections\n\nConnections link sources to destinations and define how events are processed. You can create connections, including source/destination definitions, configure authentication, add processing rules (retry, filter, transform, delay, deduplicate), and manage their lifecycle.\n\n#### Create a connection\n\nCreate a new connection between a source and destination. You can create the source and destination inline or reference existing resources:\n\n```sh\n# Basic connection with inline source and destination\n$ hookdeck gateway connection create \\\n  --source-name \"github-repo\" \\\n  --source-type GITHUB \\\n  --destination-name \"ci-system\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/webhooks\"\n\n✔ Connection created successfully\nConnection: github-repo-to-ci-system (conn_abc123)\nSource: github-repo (src_xyz789)\nSource URL: https://hkdk.events/src_xyz789\nDestination: ci-system (dst_def456)\n\n# Using existing source and destination\n$ hookdeck gateway connection create \\\n  --source-id src_existing123 \\\n  --destination-id dst_existing456 \\\n  --name \"new-connection\" \\\n  --description \"Connects existing resources\"\n```\n\n#### Add source authentication\n\nVerify webhooks from providers like Stripe, GitHub, or Shopify by adding source authentication:\n\n```sh\n# Stripe webhook signature verification\n$ hookdeck gateway connection create \\\n  --source-name \"stripe-prod\" \\\n  --source-type STRIPE \\\n  --source-webhook-secret \"whsec_abc123xyz\" \\\n  --destination-name \"payment-api\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/webhooks/stripe\"\n\n# GitHub webhook signature verification\n$ hookdeck gateway connection create \\\n  --source-name \"github-webhooks\" \\\n  --source-type GITHUB \\\n  --source-webhook-secret \"ghp_secret123\" \\\n  --destination-name \"ci-system\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://ci.example.com/webhook\"\n```\n\n#### Add destination authentication\n\nSecure your destination endpoint with bearer tokens, API keys, or basic authentication:\n\n```sh\n# Destination with bearer token\n$ hookdeck gateway connection create \\\n  --source-name \"webhook-source\" \\\n  --source-type HTTP \\\n  --destination-name \"secure-api\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/webhooks\" \\\n  --destination-bearer-token \"bearer_token_xyz\"\n\n# Destination with API key\n$ hookdeck gateway connection create \\\n  --source-name \"webhook-source\" \\\n  --source-type HTTP \\\n  --destination-name \"api-endpoint\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/webhooks\" \\\n  --destination-api-key \"your_api_key\"\n\n# Destination with custom headers\n$ hookdeck gateway connection create \\\n  --source-name \"webhook-source\" \\\n  --source-type HTTP \\\n  --destination-name \"custom-api\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/webhooks\"\n```\n\n#### Configure retry rules\n\nAdd automatic retry logic with exponential or linear backoff:\n\n```sh\n# Exponential backoff retry strategy\n$ hookdeck gateway connection create \\\n  --source-name \"payment-webhooks\" \\\n  --source-type STRIPE \\\n  --destination-name \"payment-api\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/payments\" \\\n  --rule-retry-strategy exponential \\\n  --rule-retry-count 5 \\\n  --rule-retry-interval 60000\n```\n\n#### Add event filters\n\nFilter events based on request body, headers, path, or query parameters:\n\n```sh\n# Filter by event type in body\n$ hookdeck gateway connection create \\\n  --source-name \"events\" \\\n  --source-type HTTP \\\n  --destination-name \"processor\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/process\" \\\n  --rule-filter-body '{\"event_type\":\"payment.succeeded\"}'\n\n# Combined filtering\n$ hookdeck gateway connection create \\\n  --source-name \"shopify-webhooks\" \\\n  --source-type SHOPIFY \\\n  --destination-name \"order-processor\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/orders\" \\\n  --rule-filter-body '{\"type\":\"order\"}' \\\n  --rule-retry-strategy exponential \\\n  --rule-retry-count 3\n```\n\n#### Configure rate limiting\n\nControl the rate of event delivery to your destination:\n\n```sh\n# Limit to 100 requests per minute\n$ hookdeck gateway connection create \\\n  --source-name \"high-volume-source\" \\\n  --source-type HTTP \\\n  --destination-name \"rate-limited-api\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com/endpoint\" \\\n  --destination-rate-limit 100 \\\n  --destination-rate-limit-period minute\n```\n\n#### Upsert connections\n\nCreate or update connections idempotently based on connection name - perfect for CI/CD and infrastructure-as-code workflows:\n\n```sh\n# Create if doesn't exist, update if it does\n$ hookdeck gateway connection upsert my-connection \\\n  --source-name \"stripe-prod\" \\\n  --source-type STRIPE \\\n  --destination-name \"api-prod\" \\\n  --destination-type HTTP \\\n  --destination-url \"https://api.example.com\"\n\n# Partial update of existing connection\n$ hookdeck gateway connection upsert my-connection \\\n  --description \"Updated description\" \\\n  --rule-retry-count 5\n\n# Preview changes without applying (dry-run)\n$ hookdeck gateway connection upsert my-connection \\\n  --description \"New description\" \\\n  --dry-run\n\n-- Dry Run: UPDATE --\nConnection 'my-connection' (conn_123) will be updated with the following changes:\n- Description: \"New description\"\n```\n\n#### List and filter connections\n\nView all connections with flexible filtering options:\n\n```sh\n# List all connections\n$ hookdeck gateway connection list\n\n# Filter by source or destination\n$ hookdeck gateway connection list --source-id src_abc123\n$ hookdeck gateway connection list --destination-id dst_def456\n\n# Filter by name pattern\n$ hookdeck gateway connection list --name \"production-*\"\n\n# Include disabled connections\n$ hookdeck gateway connection list --disabled\n\n# Output as JSON\n$ hookdeck gateway connection list --output json\n```\n\n#### Get connection details\n\nView detailed information about a specific connection:\n\n```sh\n# Get by ID\n$ hookdeck gateway connection get conn_123abc\n\n# Get by name\n$ hookdeck gateway connection get \"my-connection\"\n\n# Get as JSON\n$ hookdeck gateway connection get conn_123abc --output json\n\n# Include destination authentication credentials\n$ hookdeck gateway connection get conn_123abc --include-destination-auth --output json\n```\n\n#### Connection lifecycle management\n\nControl connection state and event processing behavior:\n\n```sh\n# Disable a connection (stops receiving events entirely)\n$ hookdeck gateway connection disable conn_123abc\n\n# Enable a disabled connection\n$ hookdeck gateway connection enable conn_123abc\n\n# Pause a connection (queues events without forwarding)\n$ hookdeck gateway connection pause conn_123abc\n\n# Resume a paused connection\n$ hookdeck gateway connection unpause conn_123abc\n```\n\n**State differences:**\n- **Disabled**: Connection stops receiving events entirely\n- **Paused**: Connection queues events but doesn't forward them (useful during maintenance)\n\n#### Delete a connection\n\nDelete a connection permanently:\n\n```sh\n# Delete with confirmation prompt\n$ hookdeck gateway connection delete conn_123abc\n\n# Delete by name\n$ hookdeck gateway connection delete \"my-connection\"\n\n# Skip confirmation\n$ hookdeck gateway connection delete conn_123abc --force\n```\n\nFor complete flag documentation and all examples, see [REFERENCE.md](REFERENCE.md).\n\n## Configuration files\n\nThe Hookdeck CLI uses configuration files to store the your keys, project settings, profiles, and other configurations.\n\n### Configuration file name and locations\n\nThe CLI will look for the configuration file in the following order:\n\n1. The `--config` flag, which allows you to specify a custom configuration file name and path per command.\n2. The local directory `.hookdeck/config.toml`.\n3. The default global configuration file location.\n\n### Default configuration Location\n\nThe default configuration location varies by operating system:\n\n- **macOS/Linux**: `~/.config/hookdeck/config.toml`\n- **Windows**: `%USERPROFILE%\\.config\\hookdeck\\config.toml`\n\nThe CLI follows the [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) on Unix-like systems, respecting the `XDG_CONFIG_HOME` environment variable if set.\n\n### Configuration File Format\n\nThe Hookdeck CLI configuration file is stored in TOML format and typically includes:\n\n```toml\napi_key = \"api_key_xxxxxxxxxxxxxxxxxxxx\"\nproject_id = \"tm_xxxxxxxxxxxxxxx\"\nproject_mode = \"inbound\" | \"console\"\n```\n\n### Local Configuration\n\nThe Hookdeck CLI also supports local configuration files. If you run the CLI commands in a directory that contains a `.hookdeck/config.toml` file, the CLI will use that file for configuration instead of the global one.\n\n### Using Profiles\n\nThe `config.toml` file supports profiles which give you the ability to save different CLI configuration within the same configuration file.\n\nYou can create new profiles by either running `hookdeck login` or `hookdeck use` with the `-p` flag and a profile name. For example:\n\n```sh\nhookdeck login -p dev\n```\n\nIf you know the name of your Hookdeck organization and the project you want to use with a profile you can use the following:\n\n```sh\nhookdeck project use org_name proj_name -p prod\n```\n\nThis will results in the following config file that has two profiles:\n\n```toml\nprofile = \"dev\"\n\n[dev]\n  api_key = \"api_key_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\"\n  project_id = \"tm_5JxTelcYxOJy\"\n  project_mode = \"inbound\"\n\n[prod]\n  api_key = \"api_key_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy\"\n  project_id = \"tm_U9Zod13qtsHp\"\n  project_mode = \"inbound\"\n```\n\nThis allows you to run commands against different projects. For example, to listen to the `webhooks` source in the `dev` profile, run:\n\n```sh\nhookdeck listen 3030 webhooks -p dev\n```\n\nTo listen to the `webhooks` source in the `prod` profile, run:\n\n```sh\nhookdeck listen 3030 webhooks -p prod\n```\n\n## Global Flags\n\nThe following flags can be used with any command:\n\n- `--api-key`: Your API key to use for the command.\n- `--color`: Turn on/off color output (on, off, auto).\n- `--config`: Path to a specific configuration file.\n- `--device-name`: A unique name for your device.\n- `--insecure`: Allow invalid TLS certificates.\n- `--log-level`: Set the logging level (debug, info, warn, error).\n- `--profile` or `-p`: Use a specific configuration profile.\n\nThere are also some hidden flags that are mainly used for development and debugging:\n\n*   `--api-base`: Sets the API base URL.\n*   `--dashboard-base`: Sets the web dashboard base URL.\n*   `--console-base`: Sets the web console base URL.\n*   `--ws-base`: Sets the Websocket base URL.\n\n## Troubleshooting\n\n### Homebrew: Binary Already Exists Error\n\nIf you previously installed Hookdeck via the Homebrew formula and are upgrading to the cask version, you may see:\n\n```\nWarning: It seems there is already a Binary at '/opt/homebrew/bin/hookdeck'\nfrom formula hookdeck; skipping link.\n```\n\nTo resolve this, uninstall the old formula version first, then install the cask:\n\n```sh\nbrew uninstall hookdeck\nbrew install --cask hookdeck/hookdeck/hookdeck\n```\n\n\n## Developing\n\nRunning from source:\n\n```sh\ngo run main.go\n```\n\n### Generating REFERENCE.md\n\nThe [REFERENCE.md](REFERENCE.md) file is generated from Cobra command metadata. After changing commands, flags, or help text, regenerate it:\n\n```sh\ngo run ./tools/generate-reference --input REFERENCE.template.md --output REFERENCE.md\n```\n\nTo validate that REFERENCE.md is up to date (useful in CI):\n\n```sh\ngo run ./tools/generate-reference --input REFERENCE.template.md --output REFERENCE.md --check\n```\n\nBuild from source by running:\n\n```sh\ngo build\n```\n\nThen run the locally generated `hookdeck-cli` binary:\n\n```sh\n./hookdeck-cli\n```\n\n### Testing the npm package build\n\nTo test the npm package build process locally (including the wrapper script), you can use the automated test script:\n\n```sh\n# Run the automated test script (recommended)\n./test-scripts/test-npm-build.sh\n```\n\nThe test script will:\n- Build all 6 platform binaries using GoReleaser\n- Verify the binaries directory structure\n- Test the wrapper script on your current platform\n- Verify npm pack includes all required files\n\n**Manual testing (if you prefer step-by-step):**\n\n```sh\n# Install GoReleaser (if not already installed)\n# Option 1: Using Homebrew (recommended on macOS)\nbrew install goreleaser\n\n# Option 2: Download binary from GitHub releases\n# Visit https://github.com/goreleaser/goreleaser/releases/latest\n\n# Build all platform binaries for npm\ngoreleaser build -f .goreleaser/npm.yml --snapshot --clean\n\n# Verify binaries directory structure\nls -R binaries/\n\n# Test the wrapper script on your platform\nnode bin/hookdeck.js --version\n\n# Test npm package creation (dry-run)\nnpm pack --dry-run\n```\n\nThis will create the `binaries/` directory with all 6 platform binaries, allowing you to test the wrapper script locally before publishing.\n\n## Testing\n\n### Running Acceptance Tests\n\nThe Hookdeck CLI includes comprehensive acceptance tests written in Go. These tests verify end-to-end functionality by executing the CLI and validating outputs.\n\n**Local testing:**\n\n```bash\n# Run all acceptance tests\ngo test ./test/acceptance/... -v\n\n# Run specific test\ngo test ./test/acceptance/... -v -run TestCLIBasics\n\n# Skip acceptance tests (short mode)\ngo test ./test/acceptance/... -short\n```\n\n**Environment setup:**\n\nFor local testing, create a `.env` file in `test/acceptance/`:\n\n```bash\n# test/acceptance/.env\nHOOKDECK_CLI_TESTING_API_KEY=your_api_key_here\n```\n\n**CI/CD:**\n\nIn CI environments, set the `HOOKDECK_CLI_TESTING_API_KEY` environment variable directly in your workflow configuration or repository secrets.\n\nFor detailed testing documentation and troubleshooting, see [`test/acceptance/README.md`](test/acceptance/README.md).\n\n### Testing npm package and wrapper script\n\nThe npm package includes a wrapper script (`bin/hookdeck.js`) that detects the platform and executes the correct binary. \n\n**Quick test (using automated script):**\n\n```sh\n./test-scripts/test-npm-build.sh\n```\n\n**Manual testing:**\n\n```sh\n# Ensure GoReleaser is installed (see \"Testing the npm package build\" section above)\n\n# Build all platform binaries\ngoreleaser build -f .goreleaser/npm.yml --snapshot --clean\n\n# Test wrapper script on current platform\nnode bin/hookdeck.js version\n\n# Verify wrapper script can find binary\nnode bin/hookdeck.js --help\n\n# Test npm pack includes all files\nnpm pack --dry-run | grep -E \"(bin/hookdeck.js|binaries/)\"\n```\n\n**Note:** The wrapper script expects binaries in `binaries/{platform}-{arch}/hookdeck[.exe]`. When building locally, ensure all platforms are built or the wrapper will fail for missing platforms.\n\n### Testing against a local API\n\nWhen testing against a non-production Hookdeck API, you can use the\n`--api-base` and `--ws-base` flags, e.g.:\n\n```sh\n./hookdeck-cli --api-base http://localhost:9000 --ws-base ws://localhost:3003 listen 1234\n```\n\nAlso if running in Docker, the equivalent command would be:\n\n```sh\ndocker run --rm -it \\\n    -v $HOME/.config/hookdeck:/root/.config/hookdeck hookdeck/hookdeck-cli \\\n    --api-base http://host.docker.internal:9000 \\\n    --ws-base ws://host.docker.internal:3003 \\\n    listen \\\n    http://host.docker.internal:1234\n```\n\n### Testing the published npm package\n\nTo verify that the published npm package installs correctly and has the expected layout (wrapper script and platform binaries), use the local test script. It installs into a controlled directory (no global install) and runs the same checks as the `test-npm-install` CI workflow.\n\n```sh\n# Test with @latest (default)\n./test-scripts/test-npm-install-local.sh\n\n# Test with a specific version or tag\n./test-scripts/test-npm-install-local.sh 1.7.1\n./test-scripts/test-npm-install-local.sh @beta\n```\n\nInstall output is written to `test-scripts/.install-test/` (gitignored).\n\n## Releasing\n\nThis section describes the release process for the Hookdeck CLI.\n\n## Release Process\n\nThe release workflow supports tagging from **ANY branch** - it automatically detects which branch contains the tag. This means you can create beta releases directly from feature branches for testing before merging to `main`.\n\n### Stable Release (Preferred Method: GitHub UI)\n\n1. Ensure all tests pass on `main`\n2. Go to the [GitHub Releases page](https://github.com/hookdeck/hookdeck-cli/releases)\n3. Click \"Draft a new release\"\n4. Create a new tag with a stable version (e.g., `v1.3.0`)\n5. Target the `main` branch\n6. Generate release notes or write them manually\n7. Publish the release\n\nThe GitHub Actions workflow will automatically:\n- Build binaries for all platforms\n- Create a stable GitHub release\n- Publish to NPM with the `latest` tag\n- Update package managers:\n  - Homebrew: `hookdeck` formula\n  - Scoop: `hookdeck` package\n  - Docker: Updates both the version tag and `latest`\n\n**Alternative (Command Line):**\n```bash\ngit checkout main\ngit tag v1.3.0\ngit push origin v1.3.0\n# Then create release notes on GitHub Releases page\n```\n\n### Pre-release from Main (General Beta Testing)\n\nFor general beta testing of features that have been merged to `main`:\n\n**Preferred Method: GitHub UI**\n1. Ensure `main` branch is in the desired state\n2. Go to the [GitHub Releases page](https://github.com/hookdeck/hookdeck-cli/releases)\n3. Click \"Draft a new release\"\n4. Create a new tag with pre-release version (e.g., `v1.3.0-beta.1`)\n5. Target the `main` branch\n6. Check \"Set as a pre-release\"\n7. Publish the release\n8. GitHub Actions will build and publish with npm tag `beta`\n\n**Alternative (Command Line):**\n```bash\ngit checkout main\ngit tag v1.3.0-beta.1\ngit push origin v1.3.0-beta.1\n```\n\n**Installing beta releases:**\n\n```sh\n# NPM\nnpm install hookdeck-cli@beta -g\n\n# Homebrew\nbrew install hookdeck/hookdeck/hookdeck-beta\n\n# To force the symlink update and overwrite all conflicting files:\n# brew link --overwrite hookdeck-beta\n\n# Scoop\nscoop install hookdeck-beta\n\n# Docker\ndocker run hookdeck/hookdeck-cli:v1.3.0-beta.1 version\n```\n\n### Pre-release from Feature Branch (Feature-Specific Testing)\n\nFor testing a specific feature in isolation before merging to main:\n\n**Preferred Method: GitHub UI**\n1. Ensure your feature branch is pushed to origin\n2. Go to the [GitHub Releases page](https://github.com/hookdeck/hookdeck-cli/releases)\n3. Click \"Draft a new release\"\n4. Create a new tag with pre-release version (e.g., `v1.3.0-beta.1`)\n5. Target your feature branch (e.g., `feat/my-feature`)\n6. Check \"Set as a pre-release\"\n7. Add notes about what's being tested\n8. Publish the release\n9. GitHub Actions will automatically detect the branch and build from it\n\n**Alternative (Command Line):**\n```bash\ngit checkout feat/my-feature\ngit tag v1.3.0-beta.1\ngit push origin v1.3.0-beta.1\n# Then create release notes on GitHub Releases page\n```\n\n**Installing beta releases:**\n\n```sh\n# NPM\nnpm install hookdeck-cli@beta -g\n\n# Homebrew\nbrew install hookdeck/hookdeck/hookdeck-beta\n\n# To force the symlink update and overwrite all conflicting files:\n# brew link --overwrite hookdeck-beta\n\n# Scoop\nscoop install hookdeck-beta\n\n# Docker\ndocker run hookdeck/hookdeck-cli:v1.3.0-beta.1 version\n```\n\n**Note:** Only stable releases (without pre-release identifiers like `-beta`, `-alpha`) will update the `latest` tags across all distribution channels.\n\n## Repository Setup\n\n### GitHub Repository Settings\n\nTo maintain code quality and protect the main branch, configure the following settings in your GitHub repository:\n\n**Default Branch:**\n1. Go to Settings → Branches\n2. Set default branch to `main` (if not already set)\n\n**Branch Protection Rules for `main`:**\n1. Go to Settings → Branches → Branch protection rules\n2. Add rule for `main` branch\n3. Enable the following settings:\n   - **Require a pull request before merging**\n     - Require approvals: 1 (or as needed for your team)\n   - **Require status checks to pass before merging**\n     - Require branches to be up to date before merging\n     - Add status check: `build-linux`, `build-mac`, `build-windows` (from test workflow)\n   - **Do not allow bypassing the above settings**\n   - **Restrict force pushes** (recommended)\n   - **Restrict deletions** (recommended)\n\nThese settings ensure that all changes to `main` go through proper review and testing before being merged.\n\n## License\n\nCopyright (c) Hookdeck. All rights reserved.\n\nLicensed under the [Apache License 2.0 license](LICENSE).\n","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookdeck%2Fhookdeck-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhookdeck%2Fhookdeck-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhookdeck%2Fhookdeck-cli/lists"}