# hooks.bot > Disposable webhook endpoints, and a debugger that works out why a signature is > failing. Designed to be driven by a coding agent over MCP as much as by a person in > a browser. No account, no API key, nothing to sign up for. ## MCP Endpoint: https://www.hooks.bot/mcp Transport: Streamable HTTP. No authentication. Install into Claude Code: claude mcp add --transport http hooks-bot https://www.hooks.bot/mcp Tools: - create_endpoint Create a disposable URL. Returns the URL and its id. - wait_for_request Block until a request lands (up to 55s). The one to use right after telling someone to trigger their webhook. - list_requests Recent requests at an endpoint, newest first. - get_request One captured request in full. - diagnose_signature Work out why a signature will not verify. Accepts either a captured request (endpoint_id + request_id) or a pasted body and header block. Rebuilds the signature across every plausible construction — body normalization, secret derivation, hash algorithm, digest encoding, signed-string layout — finds the one that reproduces what you were sent, and names the step that differs. The typical loop: create_endpoint -> give the URL to the user -> wait_for_request -> diagnose_signature against the captured bytes. Nothing needs copying by hand. Resources (read these rather than guessing): - hooks://guide The full workflow and how to read a diagnosis. - hooks://providers/{provider} Signature reference for one provider, generated from the same table the engine runs on. Prompts: - debug-webhook Walks the whole failing-signature loop. Optional provider argument. - capture-webhook Create an endpoint and summarise whatever arrives. The server also ships instructions that clients hand to the model on connect. ## Capture URLs Anything sent to https://www.hooks.bot/h/{id} is recorded: any method, any path beneath it, any body. Query strings, headers and source country are kept too. Sub-paths are preserved, so https://www.hooks.bot/h/{id}/stripe/events records a path of /stripe/events. Responses carry a restrictive Content-Security-Policy. These endpoints cannot serve active content and are not useful for hosting anything. ## HTTP API POST /api/endpoints Create an endpoint. GET /api/endpoints/{id} createdAt, expiresAt, count. GET /api/endpoints/{id}/requests ?limit=N, newest first. GET /api/endpoints/{id}/ws WebSocket live tail. ## Limits - Endpoints expire 24 hours after creation and delete themselves. - 200 requests retained per endpoint, oldest dropped first. - Bodies stored up to 65536 bytes; requests over 1 MB are rejected. - Endpoint ids carry roughly 80 bits of entropy. Knowing the id is the only credential, so treat one like a secret. ## The browser debugger The signature debugger at https://www.hooks.bot runs entirely client-side via Web Crypto. A signing secret pasted into that page is never sent anywhere. The MCP diagnose_signature tool is the deliberate exception: there the agent supplies the secret over its own transport. ## Providers understood by diagnose_signature - Stripe header: Stripe-Signature signs: {timestamp}.{body} digest: HMAC-SHA-256, hex, replay window 300s secret: Endpoint signing secret from the Stripe dashboard, used whole: whsec_… docs: https://docs.stripe.com/webhooks#verify-manually - GitHub header: X-Hub-Signature-256 signs: raw body digest: HMAC-SHA-256, hex secret: The webhook secret you typed when creating the webhook. No prefix, used as-is. docs: https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries - Svix / Standard Webhooks header: webhook-signature signs: {id}.{timestamp}.{body} digest: HMAC-SHA-256, base64, replay window 300s secret: whsec_… — the prefix is stripped and the remainder base64-decoded to key bytes. docs: https://www.standardwebhooks.com/ - Shopify header: X-Shopify-Hmac-Sha256 signs: raw body digest: HMAC-SHA-256, base64 secret: Your app's client secret (API secret key) — not the API key, not an access token. docs: https://shopify.dev/docs/apps/build/webhooks/subscribe/https#verify-the-webhook - Slack header: X-Slack-Signature signs: v0:{timestamp}:{body} digest: HMAC-SHA-256, hex, replay window 300s secret: Signing Secret from your app's Basic Information page — not a bot token. docs: https://api.slack.com/authentication/verifying-requests-from-slack - Paddle Billing header: Paddle-Signature signs: {timestamp}:{body} digest: HMAC-SHA-256, hex, replay window 5s secret: Notification destination secret key, pdl_ntfset_… — used as-is. docs: https://developer.paddle.com/webhooks/signature-verification - Twilio header: X-Twilio-Signature signs: URL + sorted POST params digest: HMAC-SHA-1, base64 secret: Your account Auth Token — not an API key secret. docs: https://www.twilio.com/docs/usage/security#validating-requests ## Notes for agents - A signature that verifies can still be rejected for a stale timestamp. diagnose_signature reports timestamp age separately from validity — read both. - Stripe and Svix/Standard Webhooks both issue secrets beginning whsec_ and derive keys from them completely differently. This is the single commonest failure in the category. - Twilio signs the request URL plus sorted form fields rather than the body, so diagnose_signature needs the full webhook URL for Twilio requests.