cURL: The Complete Guide for 2026

Published February 15, 2026 · 22 min read

curl is the universal Swiss army knife for HTTP. It runs everywhere (Linux, macOS, Windows), it’s scriptable, it speaks dozens of protocols, and it’s the fastest way to answer questions like:

⚙ Try it: Generate a correct command instantly with our cURL Command Builder (headers, query params, JSON body, auth, uploads). For quick copy/paste patterns, bookmark the cURL Commands Cheat Sheet.

Table of Contents

  1. What cURL is (and when to use it)
  2. Install and check your version
  3. Basic syntax and mental model
  4. GET requests and query parameters
  5. POST/PUT/PATCH/DELETE requests
  6. Headers: Accept, Content-Type, custom headers
  7. Authentication: API keys, Bearer tokens, Basic auth, .netrc
  8. Sending JSON correctly (and safely)
  9. Uploading files (multipart) and raw uploads
  10. Downloading files reliably
  11. Redirects, cookies, and sessions
  12. Proxies and debugging
  13. TLS, certificates, and mTLS
  14. Using curl in scripts: exit codes, retries, timeouts
  15. Common mistakes (and fixes)
  16. FAQ

1. What cURL is (and when to use it)

cURL is a command-line client that sends requests and prints responses. It’s ideal when you want repeatable requests (in a shell history, script, CI job, or bug report) and you need full visibility into the raw HTTP exchange.

Use curl when you care about:

2. Install and check your version

curl --version

On most Linux distributions and macOS, curl is already installed. On minimal containers, install it with your package manager:

# Debian/Ubuntu
sudo apt-get update && sudo apt-get install -y curl

# Alpine
apk add --no-cache curl

# Fedora
sudo dnf install -y curl

3. Basic syntax and mental model

The simplest curl request is just a URL:

curl https://example.com

Think of curl as:

GoalFlag(s)Example
Choose a method-Xcurl -X POST https://api.example.com
Add a header-Hcurl -H 'Accept: application/json' https://api.example.com
Send request body--data-rawcurl --data-raw 'a=1' https://api.example.com
Show status code-wcurl -w '\n%{http_code}\n' https://example.com
Follow redirects-Lcurl -L https://example.com
Verbose debug-vcurl -v https://example.com

4. GET requests and query parameters

GET requests are the default:

curl 'https://api.example.com/v1/users?page=2&limit=50'

Use -G + --data-urlencode for safer query strings

Manually building query strings gets annoying when values contain spaces or special characters. Use -G to force query-string mode, and --data-urlencode to encode values:

curl -G 'https://api.example.com/search' \
  --data-urlencode 'q=error budget' \
  --data-urlencode 'sort=created_at desc'
Tip: If you just need to quickly URL-encode something, use the URL Encode tool.

5. POST/PUT/PATCH/DELETE requests

For APIs, you’ll commonly use:

Example:

curl -X DELETE 'https://api.example.com/v1/users/123'
Heads up: If you add --data/--data-raw, curl will switch the method to POST unless you explicitly force something else with -X.

6. Headers: Accept, Content-Type, custom headers

Add headers with -H. Use one flag per header:

curl 'https://api.example.com/v1/users' \
  -H 'Accept: application/json' \
  -H 'X-Request-Id: 123e4567-e89b-12d3-a456-426614174000'

When to set Accept vs Content-Type

7. Authentication: API keys, Bearer tokens, Basic auth, .netrc

Bearer token (OAuth2 / JWT)

curl 'https://api.example.com/v1/me' \
  -H 'Authorization: Bearer YOUR_TOKEN'

Basic auth

curl -u 'username:password' 'https://api.example.com/v1/me'

Keep secrets out of shell history

Three safer options:

8. Sending JSON correctly (and safely)

When sending JSON, set Content-Type: application/json and send the body with --data-raw:

curl -X POST 'https://api.example.com/v1/users' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  --data-raw '{"name":"Alice","role":"admin"}'

Send JSON from a file

curl -X POST 'https://api.example.com/v1/users' \
  -H 'Content-Type: application/json' \
  --data-binary @payload.json
Tip: Pipe curl output through jq to pretty-print JSON (see our jq guide) or paste it into the JSON Formatter tool.

9. Uploading files (multipart) and raw uploads

Multipart form upload with -F

curl -X POST 'https://api.example.com/v1/upload' \
  -F 'file=@./report.pdf' \
  -F 'project=alpha'

Raw file upload with -T (PUT)

curl -T ./backup.tar.gz 'https://storage.example.com/backups/backup.tar.gz'

10. Downloading files reliably

Use -O to save with the remote filename, or -o to set your own file name:

# remote filename
curl -O 'https://example.com/files/archive.zip'

# custom filename
curl -o archive.zip 'https://example.com/files/archive.zip'

Resume a partial download

curl -C - -O 'https://example.com/files/archive.zip'

11. Redirects, cookies, and sessions

Follow redirects

curl -L 'https://example.com'

Store and send cookies

# Save cookies to a jar
curl -c cookies.txt 'https://example.com/login'

# Send cookies from the jar
curl -b cookies.txt 'https://example.com/dashboard'

12. Proxies and debugging

Verbose mode

curl -v 'https://api.example.com/v1/health'

Show only response headers

curl -I 'https://api.example.com/v1/health'

Use a proxy

curl -x 'http://127.0.0.1:8080' 'https://example.com'

13. TLS, certificates, and mTLS

Inspect TLS without turning verification off

If you’re diagnosing TLS issues, start with -v. Only use -k as a last resort (testing only):

curl -v 'https://self-signed.example.internal'

# Testing only
curl -k 'https://self-signed.example.internal'

Mutual TLS (mTLS)

curl 'https://mtls.example.com' \
  --cert client.crt \
  --key client.key \
  --cacert ca.crt

14. Using curl in scripts: exit codes, retries, timeouts

For scripts and CI, you usually want:

curl -sS --fail-with-body \
  --connect-timeout 5 \
  --max-time 20 \
  --retry 3 \
  --retry-delay 1 \
  'https://api.example.com/v1/health'

Capture response body and status code

status=$(curl -sS --fail-with-body \
  -o /tmp/resp.json \
  -w '%{http_code}' \
  'https://api.example.com/v1/users/123')

echo "HTTP $status"
cat /tmp/resp.json

15. Common mistakes (and fixes)

1) Getting 415 Unsupported Media Type

You likely forgot Content-Type: application/json for JSON bodies.

2) JSON parsing errors on the server

Shell quoting is a common culprit. If your JSON contains quotes or newlines, prefer sending from a file with --data-binary @payload.json.

3) “Why did curl send POST?”

Because you used -d/--data. Curl assumes POST when you provide a request body.

4) “Works in Postman but not in curl”

Compare the exact request: headers, auth, and body. Use -v in curl, and check that your API key is in the same header Postman uses.

FAQ

How do I convert a request to a curl command?

If you have a URL, headers, and a body, you can build a correct curl command with our cURL Command Builder and then tweak flags like -L, -v, and --fail-with-body.

How do I pretty-print JSON responses?

Pipe the output to jq (jq guide) or paste it into our JSON Formatter.

Frequently Asked Questions

How do I send JSON with curl?
Use -H 'Content-Type: application/json' and --data-raw. If the payload is complex, send from a file with --data-binary @payload.json.
What is the difference between -d and -F?
Use -d for request bodies like application/x-www-form-urlencoded (or JSON if you also set the header). Use -F for multipart/form-data — especially when uploading files.
How do I follow redirects with curl?
Use -L (aka --location). By default, curl prints the first response and stops, even if it’s a 301/302.
How do I make curl fail on HTTP errors in scripts?
Use --fail-with-body plus -sS. Add timeouts (--connect-timeout, --max-time) and retries (--retry) for production scripts.