← Back to PRs

#9403: feat(hooks): Support application/x-www-form-urlencoded content-type via webhooks

by chipgpt open 2026-02-05 05:52 View on GitHub →
gateway stale
### Summary This PR adds support for parsing `application/x-www-form-urlencoded` request bodies alongside JSON. ### Motivation Some third-party webhooks (e.g. Mailgun route webhooks) send payloads as `application/x-www-form-urlencoded`, and the content type cannot be configured by the client. Previously, these requests failed JSON parsing even though the payload was valid. ```ts { "body": { "ok": false, "error": "SyntaxError: No number after minus sign in JSON at position 1 (line 1 column 2)" }, "status": 400 } ``` ### Changes - Introduces a form-urlencoded body parser with size limits and repeated-key handling - Dispatches body parsing based on Content-Type - Preserves existing JSON behavior and error handling This allows webhook integrations to work correctly without requiring upstream control over request headers. <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR refactors hook request body parsing by extracting a generic `readBody()` (byte-limited raw string reader), then re-implementing `readJsonBody()` on top of it and adding a new `readFormUrlEncodedBody()` for `application/x-www-form-urlencoded`. `createHooksRequestHandler` in `src/gateway/server-http.ts` now dispatches between JSON vs form parsing based on the request `Content-Type`, preserving the existing JSON path and returning 413 on oversized payloads. <h3>Confidence Score: 3/5</h3> - This PR is mergeable after addressing a functional mismatch in how form-urlencoded bodies are consumed by the existing hook endpoints. - Core parsing changes look contained and keep JSON behavior, but the current integration in the hook handler appears to drop/ignore the urlencoded fields for the built-in hook endpoints, which would make the feature ineffective for typical webhook payloads. - src/gateway/server-http.ts, src/gateway/hooks.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> **Context used:** - Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=fd949e91-5c3a-4ab5-90a1-cbe184fd6ce8)) - Context from `dashboard` - AGENTS.md ([source](https://app.greptile.com/review/custom-context?memory=0d0c8278-ef8e-4d6c-ab21-f5527e322f13)) <!-- /greptile_comment -->

Most Similar PRs