Tools mentioned in this article
Open the browser-based tool while you read and try the workflow immediately.
Reading a pasted curl command makes API work faster
A curl command copied from documentation or your browser’s dev tools usually looks like this:
curl -X POST 'https://api.example.com/v1/items?limit=10' \
-H 'Authorization: Bearer TOKEN' \
-H 'Content-Type: application/json' \
-d '{"name":"Alice","tags":["a","b"]}'
Simple enough once you can read it — but a few option combinations change the behaviour, and not knowing them leads to “the same command doesn’t work here”. This is a reference for the common options plus the places people actually get caught.
Option cheat sheet
| Option | Meaning |
|---|---|
-X, --request | Set the HTTP method (GET / POST / PUT / DELETE) |
-H, --header | Add a request header; repeatable |
-d, --data | Send a request body. Implies POST |
--data-raw | Same as -d but does not treat a leading @ as a filename |
-F, --form | Send as multipart/form-data (file uploads) |
-u, --user | Basic auth (user:password) |
-L, --location | Follow redirects (3xx) |
-o, --output | Write the response to a file |
-O, --remote-name | Save using the filename from the URL |
-s, --silent | Hide the progress meter |
-S, --show-error | With -s, still show errors |
-i, --include | Include response headers in the output |
-I, --head | Send HEAD and show only headers |
-v, --verbose | Show the full exchange, including request headers |
-k, --insecure | Skip server certificate verification |
--compressed | Ask for a compressed transfer (gzip etc.) |
-b, --cookie | Send cookies |
-c, --cookie-jar | Save received cookies to a file |
-w, --write-out | Print details such as %{http_code} when finished |
-X POST is usually redundant
Adding -d already makes the request a POST. These two are identical:
curl -X POST https://api.example.com/items -d '{"a":1}'
curl https://api.example.com/items -d '{"a":1}'
The problem is the opposite case. -X GET together with -d produces a GET request with a body — something proxies and servers may ignore or reject, which is a classic “works locally, fails in production” cause.
Note also that repeating -d joins the values with &. Handy for form posts, fatal for JSON:
# Not what you want: sends {"a":1}&{"b":2}
curl -d '{"a":1}' -d '{"b":2}' https://api.example.com/items
A leading @ in -d reads a file
When the value passed to -d starts with @, curl reads that file and sends its contents:
curl -d @payload.json https://api.example.com/items # sends the file contents
Useful — until you pass a username or handle verbatim:
# Intent: send the string "@alice"
# Reality: curl looks for a file called ./alice and errors if it's missing
curl -d '@alice' https://api.example.com/items
To send a value containing @ literally, use --data-raw, which gives @ no special meaning.
The Content-Type does not become JSON on its own
With -d, curl sends Content-Type: application/x-www-form-urlencoded unless you say otherwise. Send JSON without the header and the server fails to parse it:
curl -H 'Content-Type: application/json' \
-d '{"name":"Alice"}' https://api.example.com/items
curl 7.82 and later offer --json, which sets both Content-Type: application/json and Accept: application/json. Older environments don’t have it, so spell the header out in commands you intend to share.
Quoting causes more failures than anything else
| Style | Behaviour |
|---|---|
'...' (single) | Passes $ and " through untouched. Use this for JSON |
"..." (double) | The shell expands $variables |
JSON contains double quotes, so the outer quoting should be single:
# Fine
curl -d '{"name":"Alice"}' https://api.example.com/items
# The shell strips the inner quotes and the body breaks
curl -d "{"name":"Alice"}" https://api.example.com/items
When you need a token from an environment variable, mix the two deliberately:
curl -H "Authorization: Bearer $TOKEN" \
-d '{"name":"Alice"}' https://api.example.com/items
Windows Command Prompt does not treat single quotes as quoting at all, and in PowerShell curl may be an alias for Invoke-WebRequest. Call curl.exe explicitly, or run the command in WSL or Git Bash.
Quote URLs that contain &
Paste a multi-parameter URL unquoted and the shell reads & as “run in background”, truncating the command:
# Broken: only limit=10 is sent
curl https://api.example.com/items?limit=10&offset=20
# Correct
curl 'https://api.example.com/items?limit=10&offset=20'
Values with spaces or non-ASCII characters need percent-encoding. You can check an encoding with the URL encoder/decoder, or let curl build the query string safely with -G and --data-urlencode:
curl -G https://api.example.com/search --data-urlencode 'q=hello world'
Two options worth hesitating over
-k / --insecure disables certificate verification. It has a place when testing a self-signed certificate locally, but the classic incident is adding it to silence an error and leaving it in a shared or production command. Fix certificate problems at the certificate.
-L / --location follows redirects. Convenient, but the method and body handling on a redirected POST can change; pin the behaviour with --post301, --post302 or --post303 when it matters.
Turning the command into code
Once you’ve read a curl command, transcribing headers and bodies by hand into your application is error-prone. Paste it into the cURL converter to get request code for JavaScript, Python, Go and others — the quoting and header splitting are handled for you.
For formatting or validating the JSON you’re sending, use the JSON formatter; to inspect a query string, URL parameters to JSON. Everything runs in your browser, so a command containing an auth token is never transmitted anywhere.
Summary
-dalready implies POST;-X GETwith-dproduces an awkward GET-with-body- A
-dvalue starting with@reads a file — use--data-rawto send it as text -dalone means form encoding. For JSON, set the header or use--json(curl 7.82+)- Use single quotes around JSON; double quotes only where you need variable expansion
- Quote URLs containing
&; build encoded queries with-G --data-urlencode -kis not a tool for silencing errors, and-Lcan change how a POST behaves
FAQ
Do I need to write -X POST?
Usually not — adding -d or -F makes the request a POST automatically. Writing it anyway documents intent, which is worth something in a shared command. What to avoid is -X GET combined with -d: that is a GET with a body, and some servers and proxies ignore or reject it.
What is the difference between -d and --data-raw?
Only the handling of a leading @. With -d, a value starting with @ is treated as a filename and the file’s contents are sent; --data-raw sends the string as-is. Use --data-raw for data that legitimately contains @, such as an email address.
I sent JSON but the server won’t parse it
With -d, the default Content-Type is application/x-www-form-urlencoded, so you need -H 'Content-Type: application/json'. On curl 7.82 or later, --json sets the header for you.
The command doesn’t work on Windows
Command Prompt does not interpret single quotes, and PowerShell may alias curl to Invoke-WebRequest. Either call curl.exe explicitly or run the command from a shell that handles single quotes, such as WSL or Git Bash.
Is it safe to paste a command containing an auth token?
The cURL converter runs entirely in your browser and nothing you paste is transmitted. Do note that the converted code still contains the token, so move it to an environment variable before committing the code.