cURLParse cURL Converter

Example: POST with Query Params and a JSON Body

cURLParse Guides · Updated 2026-10-18 · All guides
curl -X POST 'https://api.example.com/search?mode=advanced&debug=false' \
  -H 'Content-Type: application/json' \
  -d '{"query":"bear","from":0}'

This shape is everywhere (Stripe webhooks, search APIs) and breaks converters that assume data flags imply the query string. Rules we follow: **URL is authority for params, body is authority for payload, -G is what turns data into the URL instead.**

Why it trips people up:

  • The query params are routing/behavior switches (mode, version, dryRun), not the payload. Copying -d content into the query string, or vice versa, changes which layer of the server sees your data.
  • -X POST here is load-bearing, unlike the no-op -X GET: remove it and curl still POSTs because -d implies the method — but readers of the command can't see that.
  • Quoting matters twice over: the URL contains &, which backgrounds commands in unquoted bash, and the JSON needs single quotes to stay literal. This is quoting hell in a single line.

The three layers, separated

This request has data in two places and a method switch in a third. Reading them apart is the whole skill:

layerflagswho reads it
routing/behavior switchesURL path + query (?mode=advanced)router, middleware, caches
payload-d bodythe handler / parser
method-X POST (or implied by -d)the whole line, including caches

What a server actually sees for the command above, from an echo origin:

POST /search?mode=advanced&debug=false HTTP/1.1
Content-Type: application/json
Content-Length: 26

{"query":"bear","from":0}

The query string is in the request line — visible to every proxy, CDN, and access log between you and the handler. The body is not. That's the security argument below, but it's also the caching argument: two requests differing only in body are the same cache key if the intermediary keys on URL alone. APIs that put switches in the query string avoid it; APIs that put inputs there create it.

-G inverts the whole shape

-G moves -d data into the query string and makes the request a GET:

curl -G 'https://api.example.com/search' -d 'mode=advanced' -d 'query=bear'
# GET /search?mode=advanced&query=bear
  • With -G, -d is no longer a body flag at all — it's a query-string builder that also URL-encodes. Removing -G from a converted GET turns your params into a form body the handler never reads; the API answers with defaults and no error.
  • -G + --data-urlencode is the correct way to send a param with spaces or unicode: --data-urlencode 'q=bear Grylls'. Hand-typed %20 in a URL is quoting hell — double-encoding (%2520) is the classic symptom.
  • Our converter reads -d as body and does not parse -G — verified against the shipped parser. So generated code for a -G command shows the params in the wrong place; move them by hand. The honest reading of a converted request is always: does the code put each piece of data where the transcript shows the server receiving it?

Method: -X POST here is documentation, not function

Strip -X POST and curl still POSTs, because -d implies the method (the flags guide proves it with a transcript: POST and application/x-www-form-urlencoded appear from nowhere). Keep it anyway — the reader of the command can't see the implication, and a converter that guesses method from flags has one more way to be wrong. What you must not do is keep -X POST while following a 301: the method survives the redirect but the body doesn't, and the endpoint sees an empty POST that can 200 while doing nothing. That trap is documented in curl works, my code fails.

FAQ

Is ?mode=advanced in the URL less secure than in the body? It's more exposed: query strings appear in access logs at every hop, while POST bodies usually don't. Put switches there, secrets never.

Why do webhooks use this shape? Query params survive on the URL even when middleboxes or queues round-trip the body — and signature verification reads the body verbatim, so you don't want structural switches mixed into it.

My API takes params in both places. Which wins? Whatever the handler reads. Frameworks differ: some merge query and body params with body-wins, some query-wins, some keep them separate. When both are present, assume nothing — send each key in exactly one place and assert the server's interpretation with an echo request.

Developer Sponsor / Partner
Copied to clipboard!