Guide · Webhooks · JSON · Make.com

Make.com webhook JSON: return JSON, parse it, and map nested data and arrays

Short answer: send JSON to a Make Custom webhook with Content-Type: application/json, and Make turns each key into a field you can map. Nested objects become a tree you can click through. Arrays need an Iterator to handle each item, or functions such as get() and map() to pick one value.

To answer the caller with JSON, end the scenario with Webhooks › Webhook response. Set Status (200, 400…) and a JSON Body, and add the custom header Content-Type: application/json. If the JSON arrives as one text value instead of separate fields, run it through JSON › Parse JSON.

By Flowpaja · Published · Facts checked

This guide contains an affiliate link, marked “affiliate link”.

Make webhook JSON: a JSON request with a nested customer object and an items array goes into a Custom webhook, and a Webhook response returns status 200 with a JSON body
JSON in, JSON out: the Custom webhook parses it, and the Webhook response answers.
Checked on 3 October 2026: module names and limits come from Make's app docs on apps.make.com (Webhooks, updated 4 August 2026; JSON, updated 28 May 2026) and Make's Help Center (Webhooks, 2 October 2026; Mapping arrays; general and array functions; Router). The worked example extends our free template, and its module counts come from the template's blueprint. Credits follow Make's rule of one credit per module action, so check the real numbers in your scenario's History. The curl commands were checked for syntax against a local test server, not a live Make webhook. We earn affiliate commissions from Make.

Which JSON tool for which job

You want to…UseNote
Receive JSON as mappable fieldsWebhooks › Custom webhookThe sender must use Content-Type: application/json
Turn JSON text into fieldsJSON › Parse JSONA collection {…} gives 1 bundle; an array […] gives 1 bundle per item
Answer the caller with JSON or a status codeWebhooks › Webhook responseStatus, Body, and the custom header Content-Type: application/json
Build valid JSON from mapped valuesJSON › Create JSONUses a data structure; map its output into the response Body
Handle each array item separatelyIteratorEvery module after it runs once per item
Pick one item or value from an arrayget(), first(map()), or an index in the mapping pillArrays start at 1 in get()
Turn an array into textjoin(map(…); ", ")For one cell or one line of a message
Turn many bundles into one JSONArray aggregator + Create JSON, or JSON › Aggregate to JSONFor example, a list of rows in one response
Keep the raw JSON as textJSON pass-through (webhook setting)Then parse it yourself with Parse JSON

Sources: apps.make.com Webhooks and JSON; Help Center: Mapping arrays, general functions, array functions. All checked 3 October 2026.

New to webhooks? Create one and send a first test with our Make webhook tutorial, which also covers API keys and the queue. This guide picks up from there.

What you need:

  • A Make account. Everything here works on the Free plan. If you don't have one yet, create a free Make account (affiliate link).
  • A terminal for curl: Command Prompt or PowerShell on Windows, or Terminal on Mac or Linux.
  • For the worked example, a Google Sheet.

Affiliate disclosure: the link marked "affiliate link" includes our partner code. If you sign up or later buy a paid plan through it, Flowpaja may earn a commission at no extra cost to you. More on the tools we use: best tools for Make automation.

How Make reads incoming JSON

Make's Webhooks docs describe three formats a Custom webhook accepts: a query string, form data (application/x-www-form-urlencoded or multipart/form-data), and JSON (application/json). Four details matter for JSON:

  • The header decides. JSON sent without Content-Type: application/json may not be split into fields. If the whole body arrives as one value, fix the sender's header first.
  • Make learns the structure from a real request. Run the scenario once and send a sample, or click Detect new values after the sender adds fields. If you choose a data structure in the webhook's advanced settings instead, Make validates every request against it and rejects mismatches with HTTP 400.
  • Query string and body are merged. If a request has both, Make combines them into one bundle. Where a key appears in both, the query string wins.
  • JSON pass-through (a webhook setting) hands the body on as one text string instead of fields. That's useful when you need the exact original JSON, for example to store it or forward it. Switch it off if you want fields.

The payload limit is 5 MB on every plan (Webhooks app docs). If you need to move a file, send a link to it rather than base64 data inside the JSON.

Return JSON with the Webhook response module

Without a Webhook response module, Make answers every request with status 200 and the text Accepted as soon as the request is queued. Add Webhooks › Webhook response when the caller needs a real answer, for example a website form that shows "Thanks!" or an error, or a system that retries unless it gets a certain status.

FieldWhat to enterExample
StatusAn HTTP status code200 success, 400 bad input, 303 redirect
BodyText, HTML, XML or JSON{"ok": true, "status": "created"}
Custom headersKey and value pairsKey Content-Type, value application/json

The Content-Type header isn't strictly required. Make's docs advise setting it to the matching type, and many callers only treat the body as JSON when it's there.

Four rules from Make's docs:

  • Make waits up to 180 seconds for the response. After that, the caller gets 200 Accepted instead.
  • If the scenario errors before the response, the caller gets status 500 with Scenario failed to complete.
  • Put the response last. The Help Center warns that with the response in the middle, an error in a later module doesn't deactivate the scenario, and you aren't notified. Put slow work after the response only if the caller can't wait, and add an error route to it.
  • Redirects: status 303 plus a custom header Location with the target URL sends a browser to a thank-you page.

Don't break the JSON with mapped text

Typing {"message": "{{1.message}}"} into the Body works until someone writes a quote or a line break. The body is then no longer valid JSON. Two safer options:

  • JSON › Create JSON: define a data structure (for example ok, status, id), map your values into it, and map the module's JSON string output into the Webhook response Body. Make builds the JSON from the structure, so check the output once in a test run with a value that contains quotes.
  • Only return values you control: IDs, statuses and numbers, not free text the sender just gave you.

Create JSON is a transform module, so by Make's credit rule it adds 1 credit per run.

Worked example: a lead endpoint that answers in JSON

We start from our free Webhook to Google Sheets with duplicate check template. Its blueprint has three modules: Custom webhook → Google Sheets › Search Rows (finds the request_id) → Add a Row. Two filters sit between them: one checks that request_id and email exist, and one checks that the request_id isn't in the sheet yet, which shows as Row number does not exist. The template doesn't send a Webhook response. The sender always gets Accepted.

Here we add answers, so a website or script knows what happened:

  1. Custom webhook (module 1), then a Router right after it.
  2. Route "invalid": filter: request_id does not exist OR email does not exist. Then Webhook response: Status 400, Body {"ok": false, "error": "request_id and email are required"}, header Content-Type: application/json.
  3. Route "valid", marked as the router's fallback route so it runs when the first route doesn't: Google Sheets › Search Rows on the Leads tab, filtered on request_id, limit 1. Then a second Router:
    • New: filter: Row number (from Search Rows) does not exist → Add a Row → Webhook response: Status 200, Body {"ok": true, "status": "created"}.
    • Duplicate: filter: Row number exists → Webhook response: Status 200, Body {"ok": true, "status": "duplicate"}. A retry isn't an error, so the sender shouldn't retry again.

Credits per request (Make's rule: one credit per module action; routers and filters are free):

  • Invalid: webhook + response = 2.
  • New: webhook + Search Rows + Add a Row + response = 4.
  • Duplicate: webhook + Search Rows + response = 3.

That's one more on each path than the template's measured 3 / 2 / 1 (new / duplicate / stopped by the filter), because of the response module. Check the real numbers in History after your tests.

The sender has to send a unique request_id with each submission, and the same one when it retries. The template's setup guide and test requests show the format.

Parse JSON: when JSON arrives as text

A Custom webhook already parses a normal JSON request, so you don't need Parse JSON for that. You do need it when JSON reaches your scenario as a string:

  • JSON pass-through is on
  • a form tool sends one field whose value is JSON
  • an HTTP request returns JSON as text
  • an AI module answers with JSON
  • a Google Sheets cell holds JSON

Set it up:

  1. Add JSON › Parse JSON and map the text into JSON string.
  2. For Data structure, either create one with the generator from a sample, or leave it empty. Then run the scenario once before connecting the next module, and Make builds the structure from the JSON it sees (JSON app docs).
  3. Map the parsed fields in the following modules.

Collection or array changes everything after it. A JSON string that starts with { (a collection) gives one bundle. A string that starts with [ (an array) gives one bundle per item, so every later module runs once per item and uses credits each time. If you wanted one result, wrap the array in an object on the sending side ({"items": [...]}), or aggregate afterwards.

Parse JSON fails on text that isn't pure JSON. Common causes:

  • curly quotes from a word processor
  • a trailing comma
  • an empty value
  • an AI answer wrapped in a ```json code fence or extra sentences

Look at the exact input in the module's bundle, and clean it first: for example replace() to strip the fence, or a filter that skips empty values. Ask AI models for "JSON only". Some offer a structured-output option, covered in our ChatGPT and OpenAI in Make guide.

Parse JSON is a transform module: 1 credit per run, by Make's credit rule.

Nested JSON and arrays

Take this request, which has a nested customer object and an array of items:

{
  "request_id": "req-20261003-0001",
  "customer": {
    "name": "Ana Example",
    "email": "ana@example.com",
    "address": { "city": "Tampere" }
  },
  "items": [
    { "sku": "LOGO-1", "qty": 1, "price": 290 },
    { "sku": "CARD-2", "qty": 2, "price": 45 }
  ]
}

Nested objects: in the mapping panel, open customer, then address, and click city. In a formula, get() takes a dot path, for example {{get(1.customer; address.city)}} (general functions docs). Use raw names, the ones you see when you hover over an item in the mapping panel. They're case-sensitive.

Arrays: pick the approach by what you want out of them.

GoalHowResult for the example
One row or message per itemIterator on items, then your modules2 bundles: LOGO-1, CARD-2
A specific itemMap items[] and type an index in the brackets (empty means the first item), or {{get(1.items; 2.sku)}}CARD-2
All values of one key as text{{join(map(1.items; sku); ", ")}}LOGO-1, CARD-2
The value for a given key{{first(map(1.items; price; sku; LOGO-1))}}290
How many items{{length(1.items)}}2

Function syntax from Make's Help Center (Mapping arrays, updated 23 April 2026; general and array functions, updated 4 June 2026). Arrays start at 1 in get() and in the mapping index, but slice() counts from 0. Check every formula once with Run once.

An Iterator turns one bundle into many, so everything after it multiplies. By Make's credit rule, 2 items through 3 modules is 6 credits. To get back to one bundle, for example to send one Slack message with all items, close the loop with an Array aggregator or Text aggregator. Iterator vs Aggregator explains both. Our Shopify orders guide shows the one-row-per-line-item version with real order data.

Returning a list as JSON

To answer with several records, for example "your last 5 orders", collect them into one bundle first. Make's JSON docs show the pattern:

  1. a search module (for example Google Sheets Search Rows, with a Limit)
  2. Array aggregator, with its target structure set to the Create JSON field
  3. JSON › Create JSON, with a data structure such as {"orders": [{"id": "", "total": 0}]} generated from a sample
  4. Webhook response, with the JSON string as the Body

JSON › Aggregate to JSON does the aggregation and the JSON in one module.

Testing JSON webhooks with curl

Replace YOUR-WEBHOOK-ID with your own address and keep the real URL private. The -i flag prints the status code and headers, so you can see what your Webhook response really sends back.

Mac or Linux (Terminal):

curl -i -X POST "https://hook.eu1.make.com/YOUR-WEBHOOK-ID" \
  -H "Content-Type: application/json" \
  -d '{"request_id":"req-20261003-0001","customer":{"name":"Ana Example","email":"ana@example.com"},"items":[{"sku":"LOGO-1","qty":1}]}'

Windows, nested JSON without quote trouble: save the example above as payload.json, then send the file. This works the same in Command Prompt and PowerShell, because the JSON never passes through the shell's quoting:

curl.exe -i -X POST "https://hook.eu1.make.com/YOUR-WEBHOOK-ID" -H "Content-Type: application/json" --data-binary "@payload.json"

Windows Command Prompt, inline: wrap the JSON in double quotes and write each inner quote as \":

curl -i -X POST "https://hook.eu1.make.com/YOUR-WEBHOOK-ID" -H "Content-Type: application/json" -d "{\"request_id\":\"req-20261003-0002\",\"email\":\"tom@example.org\"}"

Test the error path too: send a request without request_id (Mac or Linux syntax; on Windows, put {"email":"noid@example.net"} in a file and use the file method). With the worked example you should get HTTP/... 400 and the error JSON:

curl -i -X POST "https://hook.eu1.make.com/YOUR-WEBHOOK-ID" -H "Content-Type: application/json" -d '{"email":"noid@example.net"}'

In Windows PowerShell 5.1, the version built into Windows, curl is an alias for Invoke-WebRequest, so type curl.exe, which works in every version. Or use Invoke-RestMethod -Method Post -Uri "…" -ContentType "application/json" -Body '{"email":"ana@example.com"}', which shows only the body and throws an error on a 400 (in PowerShell 7 you can add -SkipHttpErrorCheck to see the error body).

What to expect:

  • Without a response module: 200 and Accepted.
  • With the worked example: 200 plus {"ok": true, "status": "created"} the first time, and "duplicate" for a repeat.
  • 400 Queue is full or 429 mean the queue or Make's rate limit, not your JSON. See webhook not receiving data.

Every request and response, including status, headers and body, also appears under Webhooks › your webhook › Logs › Detail. Make keeps webhook logs for 3 days, or 30 on Enterprise (Help Center: Webhooks).

Common JSON webhook problems

SymptomLikely causeFix
New keys don't appear in the mapping panelMake learned the structure from an older requestClick Detect new values and send a full sample
The whole body is one text valueWrong Content-Type, or JSON pass-through is onSend application/json, switch pass-through off, or use Parse JSON
The caller gets Accepted, not your JSONNo Webhook response was reached: a filter stopped the route, or the run took over 180 secondsGive every route a response; move slow work after it
Status 500 "Scenario failed to complete."A module errored before the responseCheck History; add an error route that sends your own error response (we haven't tested every handler type)
The caller can't read your JSONContent-Type missing, or the body was broken by quotes or line breaks in mapped textAdd the header; build the body with Create JSON
Requests rejected with 400 right awayThe webhook has a data structure and the request doesn't match itFix the sender, or relax the data structure
Only the first array item is usedAn array field was mapped into a single-value fieldIterator for each item, or join(map()) for text
Parse JSON outputs many bundlesThe JSON string is an arrayExpected; aggregate afterwards if you need one result

More error messages and their fixes: Make error cheat sheet. If you send JSON out with HTTP › Make a request, the Discord automation guide shows the choice between a JSON string and a data structure, and when each one breaks the body.

Plan check

Everything in this guide runs on Make's Free plan: Webhooks, JSON, Router, Iterator and aggregators are built-in apps. The limits that apply are the same on every plan: 5 MB per webhook payload, 300 requests per 10 seconds, and 180 seconds for a response. The one plan-dependent limit is the webhook queue, 667 items per 10,000 monthly credits (Help Center: Webhooks; pricing page, 3 October 2026). You don't need the Make Code app, which isn't on Free, or custom functions, which are Enterprise-only. Every limit and the error it causes is listed in Make timeouts and limits.

Sources checked (3 October 2026)

  • apps.make.com: Webhooks (Custom webhook, Webhook response, supported formats, JSON pass-through, 5 MB payload, 180-second response timeout, 500 "Scenario failed to complete."; updated 4 Aug 2026); JSON (Parse JSON, Create JSON, Aggregate to JSON, collection vs array; updated 28 May 2026)
  • Make Help Center: Webhooks (Webhook response placement, logs, rate limit, queue; updated 2 Oct 2026); Mapping arrays (23 Apr 2026); General functions and Array functions (4 Jun 2026); Router, including the fallback route (13 May 2026)
  • make.com/en/pricing: credit rule (each module action counts as one credit; routers don't), plan features, as seen from a US connection
  • Flowpaja's free Webhook to Sheets template: blueprint v1.0 (3 modules, 2 filters) and measured credits (3 / 2 / 1)

FAQ

How do I return JSON from a Make webhook?
Add a Webhooks › Webhook response module at the end of the route. Set Status (for example 200), put your JSON in Body, and add a header Content-Type: application/json. Build the body with JSON › Create JSON if it contains mapped text, so quotes and line breaks don't break it. Make must reach the response within 180 seconds, or the caller gets 200 Accepted instead.
Why does Make return Accepted instead of my JSON?
Accepted is the default reply when no Webhook response module ran. Usually a filter stopped the route before the response, the route that ran has no response module, or the scenario took longer than 180 seconds. Give every route its own response and move slow steps after it.
How do I parse a JSON string in Make?
Use JSON › Parse JSON and map the text into JSON string. Either generate a data structure from a sample, or run the scenario once so Make learns the structure. A JSON object gives one bundle; a JSON array gives one bundle per item, so the modules after it run once for each item.
Why does my whole webhook body arrive as one text field?
The sender didn't send Content-Type: application/json, or JSON pass-through is switched on in the webhook settings. Fix the header or switch pass-through off, then click Detect new values in the Custom webhook module and send a new sample. You can also parse the text with Parse JSON.
How do I get one item from a JSON array in Make?
Map the array and type the position in the square brackets (empty means the first item), or use get(), for example {{get(1.items; 2.sku)}} for the second item's sku. To pick by a value, use first(map(1.items; price; sku; LOGO-1)). Arrays start at 1 in get().
How do I loop over a JSON array in Make?
Use the Iterator module on the array: it outputs one bundle per item, and the modules after it run once for each, which also uses credits for each. To combine the results again into one bundle, add an Array aggregator or Text aggregator after the loop.
Can a Make webhook return different status codes?
Yes. Put a Router after the webhook and end each route with its own Webhook response, for example 400 with an error JSON for invalid input and 200 for success. If the scenario contains a Webhook response module and a module errors before a response is sent, Make returns status 500 with the text Scenario failed to complete.
How do I test a Make webhook with curl?
Send a POST with the header Content-Type: application/json and your JSON body, and add -i to see the status code and headers. On Windows, save the JSON as payload.json and send it with --data-binary "@payload.json" to avoid quoting problems. The webhook's Logs show each request and response.

Start from a working webhook build

Our free Webhook to Google Sheets template receives JSON, checks for duplicates by request ID and adds only new rows. Add the Webhook response routes from this guide on top. The same build is in Make's template gallery.

Webhook returning the wrong thing, or data not mapping? Send us the blueprint and a sample request: fix and debug on Fiverr, from $25. It's fully async: no logins and no calls. For more ready-made builds, see the Make Starter Bundle.

← All guides · All templates

Make, Google, Google Sheets, Windows, Shopify, Discord and OpenAI are trademarks of their owners. Flowpaja is independent and not affiliated with or endorsed by them. Limits, plans and prices change; check Make's current pricing page and Help Center.