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

OptionMeaning
-X, --requestSet the HTTP method (GET / POST / PUT / DELETE)
-H, --headerAdd a request header; repeatable
-d, --dataSend a request body. Implies POST
--data-rawSame as -d but does not treat a leading @ as a filename
-F, --formSend as multipart/form-data (file uploads)
-u, --userBasic auth (user:password)
-L, --locationFollow redirects (3xx)
-o, --outputWrite the response to a file
-O, --remote-nameSave using the filename from the URL
-s, --silentHide the progress meter
-S, --show-errorWith -s, still show errors
-i, --includeInclude response headers in the output
-I, --headSend HEAD and show only headers
-v, --verboseShow the full exchange, including request headers
-k, --insecureSkip server certificate verification
--compressedAsk for a compressed transfer (gzip etc.)
-b, --cookieSend cookies
-c, --cookie-jarSave received cookies to a file
-w, --write-outPrint 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

StyleBehaviour
'...' (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

  • -d already implies POST; -X GET with -d produces an awkward GET-with-body
  • A -d value starting with @ reads a file — use --data-raw to send it as text
  • -d alone 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
  • -k is not a tool for silencing errors, and -L can 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.