HTTP module fails with 422 creating an Airtable webhook, but identical request works via curl/Airtable's own testhttp

:bullseye: What is your goal?

Create an Airtable webhook subscription (POST /v0/bases/{baseId}/webhooks) from an HTTP > Make a request module, so my scenario gets an instant push notification instead of polling Airtable.

:thinking: What is the problem & what have you tried?

Same 422 every time, regardless of base, notificationUrl, or recordChangeScope presence. Airtable support ran the identical request directly (bypassing Make) with the same PAT and base and it succeeded immediately - they confirmed the account, token scopes, and base are all healthy, and pointed at how Make assembles/sends the request as the likely difference. I’ve varied the URL, tried with/without recordChangeScope, tried a brand new empty base - always the same failure via Make’s HTTP module.

:clipboard: Error messages or input/output bundles

Request: POST https://api.airtable.com/v0/bases/{baseId}/webhooks
Headers: Authorization: Bearer {PAT}, Content-Type: application/json
Body type: raw
Body: {“notificationUrl”: “https://blue-meadow-06.webhook.cool/”, “specification”: {“options”: {“filters”: {“dataTypes”: [“tableData”], “recordChangeScope”: “tblXXXXXXXXXXXXXX”}}}}

Response (every time): 422 {“error”:{“type”:“INVALID_REQUEST_UNKNOWN”,“message”:“Invalid request: parameter validation failed. Check your request data.”}}

Since Airtable ran the same request with the same token and the same base and it went through, the open question is no longer what the payload should contain. It is what Make actually puts on the wire. Everything below is aimed at making that visible rather than guessing at the payload again.

Start by capturing the outgoing request. Point the same HTTP module at an endpoint you control, for example a Make custom webhook sitting in a second scenario, run it once, and read the headers and the raw body that arrive there. Then compare that against the curl call line by line. A 422 that only appears through Make means one of those two differs, and this tells you which one.

Three things commonly differ in the HTTP module, and all three end in a generic validation error instead of a useful one.

Content type. With Body type set to Raw you also choose the content type for the request in the module. If that is left on anything other than JSON, the body leaves Make as plain text and Airtable rejects it during validation. The opposite case is just as common: the content type is chosen in the dropdown and a Content-Type header is added by hand as well, so the request goes out with two of them. Keep the Authorization header manual and let the dropdown set the content type.

Typography. If the body was pasted in from a document, a chat or a support thread, the double quotes can arrive as typographic quotes. The body is then not valid JSON at all, while looking identical in the editor. Retyping it by hand in the field rules this out, and the captured request above shows it immediately.

Mapped values. If the notification URL or the table id come from a mapping, what you read in the module configuration is not what was sent. Open the run in the scenario History and read the Input bundle of the HTTP module, which shows the body as it was assembled at runtime.

If the captured request turns out to be identical to the curl one, narrow the payload instead. Send a minimal body with only the notification URL and the specification carrying the data types filter, nothing else. If that passes, add one field back per run. Airtable answers with INVALID_REQUEST_UNKNOWN without naming the parameter it objects to, so removing fields is the only way to locate it.

For the longer run it is worth not hand building the JSON string at all. A JSON module set to Create JSON in front of the HTTP module, with the structure defined once and only its output mapped into the request body, takes escaping and typography out of the picture entirely.

One thing I’d check first is the raw JSON itself.

The body in your post contains smart quotes like “notificationUrl” instead of normal JSON quotes. If those are actually in the Make request and not just forum formatting I’d replace them first.

I’d also try letting Make build the JSON rather than sending it as manually written raw text.

If it still returns 422 I’d send the Make request and the working curl request to something like webhook.site temporarily and compare the actual body and headers they send.

At this point I’d focus on the wire request rather than Airtable permissions since the same token and base already work outside Make.