You found a public JSON endpoint that returns an array of objects — an API, an open-data feed, a CMS export — and you want it in a spreadsheet so non-technical teammates can pivot it. Curl-to-jq-to-CSV pipelines work but they're command-line and not portable. This template fetches any JSON-array endpoint and downloads the result as a clean CSV. The default points at jsonplaceholder for safe testing; swap the URL and it works against any equivalent endpoint. Useful for analysts, data journalists, or anyone doing exploratory work who'd rather skip writing a script.
How this workflow works
Three blocks. This is the leanest possible ETL pipeline: extract (HTTP), transform (auto-flatten), load (browser download).
manual_trigger— Sidepanel Run. Exposes two inputs:endpoint(defaulthttps://jsonplaceholder.typicode.com/posts) andoutfile(defaultposts.csv). You're prompted to confirm or override these per run.http_request— AGETagainst{{vars.input.endpoint}}.timeoutMs: 10000caps the request at 10 seconds;responseType: "json"tells the block to parse the response body. The parsed body — assumed to be an array of objects — is exposed as$('Fetch JSON feed').body.export_data— Takes that body, generates a CSV with column headers derived from the keys of the first object, and triggers a browser download with filename{{vars.input.outfile}}. Nested objects and arrays inside the JSON get JSON-stringified into single CSV cells.
The whole thing runs in 1-3 seconds against a fast endpoint. Output is a standard UTF-8 CSV with comma separator, which opens cleanly in Excel, Numbers, and Google Sheets.
Customising it for your case
The template is intentionally generic — most customisation lives in the inputs and the JSON shape.
- Pull from a real API. Swap the default
endpointto something useful:https://api.github.com/users/torvalds/repos, your company's internal data endpoint, a weather API, or any public CMS exposing JSON. As long as the response is a top-level array, the CSV conversion works. - Authenticated endpoints. Add headers to the
http_requestblock. Example:[{"key": "Authorization", "value": "Bearer {{env.MY_API_TOKEN}}"}]. Store the token in Settings → Env first. - Pick a subset of fields. The CSV exports all fields by default. If the API returns 50 columns and you only want 5, insert a
set_variableblock betweenhttp_requestandexport_datato remap the array. Use thejavascript_codeblock to project the array:body.map(r => ({id: r.id, title: r.title, user: r.userId})).
Common gotchas
Three honest pitfalls. First: the template assumes the response is a top-level JSON array. If the API wraps results in {data: [...]} or {posts: [...]}, the export_data block won't auto-flatten — it'll try to CSV-ify the wrapper object, producing one row. Insert a set_variable block to extract the inner array: {{$('Fetch JSON feed').body.data}}. Second: rate limits. Public APIs throttle aggressively — running this every minute on jsonplaceholder is fine, but most production APIs cap unauthenticated requests at 60/hour or less. Third: nested objects (e.g. {user: {name: "X", id: 1}}) get JSON-stringified into one cell. If you want them flattened (user.name as a column), you'll need a transform step.
FAQ
Do I need an API key? Not for the default endpoint (jsonplaceholder is public, unauthenticated). For real endpoints, store the key in env and reference it via {{env.KEY_NAME}} in the request headers.
How is this different from curl | jq | csvkit? Same end result, no command line. This template lives in your browser, can be saved and shared, and triggers a real browser download — handy if you want non-developer teammates to run the same pipeline.
What if the API returns paginated results? This template only handles a single page. For pagination, you'll need a loop block that increments a page query param and accumulates results in a set_variable array, then exports the merged set. Automa and n8n have built-in "pagination" handling; in BNOD you wire it up explicitly, which is more verbose but easier to reason about.