Good Webhooks

Use with AI agents

Give coding agents the docs as Markdown, an Agent Skill, an MCP server, the rules they most often get wrong, and prompts that work.

Every page is available as plain Markdown. Coding agents read it more reliably than HTML.

ResourceWhat it is
/llms.txtAn index of every page, grouped by section, with links to the Markdown versions
/llms-full.txtAll the docs in one Markdown file
/docs/<page>.mdAny page: add .md to its URL, for example /docs/quick-start.md
Accept: text/markdownAny page URL returns Markdown when the request prefers it
Copy Markdown and Open inButtons at the top of every page. Send the page to ChatGPT, Claude, Cursor, and others

The Markdown includes the type-checked example files and the generated type tables, so an agent sees the same code you do. The docs describe the latest beta; pin that version.

Install the skill

The package ships an Agent Skill with setup steps, code templates, and the rules below. It lives in node_modules/good-webhooks/skills/good-webhooks/, so it always matches your installed version.

npx skills add pplytas/good-webhooks

Connect the MCP server

https://good-webhooks.dev/api/mcp is a Model Context Protocol server with three tools: list_pages, get_page, and search. No sign-in needed.

claude mcp add --transport http good-webhooks https://good-webhooks.dev/api/mcp

Or add the rules to your project

Without the skill, paste this into your AGENTS.md, CLAUDE.md, or your editor's rules file. It points the agent at the docs and lists the mistakes agents make most often with this library.

AGENTS.md
## Good Webhooks

Docs: https://good-webhooks.dev/llms.txt (fetch the linked .md pages for details)

- Receivers must pass the raw request body (string or bytes) to `parseWebhook()`. Never parsed JSON.
- Receivers must record `event.id` in the same transaction as their change. Delivery is at least once.
- Respond 400 only for SIGNATURE_INVALID, SIGNATURE_EXPIRED, PAYLOAD_INVALID. Other errors are 500 so the sender retries.
- `publish()` only stores the event. Nothing is sent unless a worker runs `worker.run()` or `worker.runOnce()`.
- Load `WEBHOOK_ENCRYPTION_KEY` from secrets. Never call `generateEncryptionKey()` at startup.
- Apply SQL from `getPostgresMigration()` with the migration tool. The library never runs migrations.
- `forScope()` does not authorize. Check the caller's access before choosing a scope.
- Publish with `{ transaction: client }` when the business write uses the same database.
- `allowLocalhost: true` is for local development only.

Prompts to try

Read https://good-webhooks.dev/docs/quick-start.md and follow it in a new
directory. Run the script and show me the output.

Source

The docs source is in apps/docs/content/docs. The public API is in packages/good-webhooks/src and ships with type declarations.

On this page