cURL Command Cheat Sheet: Every Flag You Actually Need
The cURL flags developers actually use: sending headers, request bodies, authentication, following redirects, debugging, and saving output — with copy-paste examples.
Why cURL is still essential in 2026
Every few years someone declares that cURL is obsolete — replaced by Postman, by HTTPie, by browser DevTools, by whatever the current GUI favourite is. And every time, working developers keep reaching for cURL anyway. There is a good reason for that: no other tool combines the reach, the portability, and the shareability of a plain cURL command.
A cURL command is reproducible in a way that a GUI session is not. You can paste it directly into a ticket, a pull request description, a Slack thread, or a runbook and the recipient can run it immediately — on their machine, in a CI step, inside a Docker container, over SSH to a remote server. There is no "export this collection" step, no credentials stored in a shared workspace, no tool version to match. It is just text.
It is also scriptable without ceremony. Drop a cURL command into a shell script and it works. Chain it with jq to parse the response. Add it to a cron job for a lightweight health check. This composability with the rest of the Unix toolchain is something no GUI tool can replicate. The goal of this cheat sheet is not to catalogue every one of cURL's 250-odd options — it is to give you the flags that actually appear in day-to-day API work, with copy-paste examples for each.
Basic request structure: GET, POST, PUT, DELETE, PATCH
By default, cURL sends a GET request. To use any other HTTP method, pass the -X flag followed by the method name. The method name is case-sensitive and must be uppercase.
# GET (default — no -X needed)
curl https://api.example.com/users/42
# POST
curl -X POST https://api.example.com/users
# PUT
curl -X PUT https://api.example.com/users/42
# PATCH
curl -X PATCH https://api.example.com/users/42
# DELETE
curl -X DELETE https://api.example.com/users/42Note that when you use -d to send a request body, cURL automatically switches to POST even without an explicit -X POST. For PUT and PATCH you always need the explicit flag.
Sending headers with -H
The -H flag adds a request header. You can use it multiple times to send multiple headers. The most common patterns are setting Content-Type to describe the body format,Accept to tell the server what response format you want, and Authorizationto authenticate the request.
# Send a JSON Content-Type header
curl -X POST https://api.example.com/users -H "Content-Type: application/json"
# Request a JSON response
curl https://api.example.com/users -H "Accept: application/json"
# Multiple headers at once
curl https://api.example.com/users -H "Content-Type: application/json" -H "Accept: application/json" -H "X-Request-ID: abc123"
# Custom header for an API that uses its own naming scheme
curl https://api.example.com/data -H "X-Api-Version: 2"}Request bodies: -d, JSON, and --data-binary
The -d flag (short for --data) sends a request body. Without aContent-Type header, cURL defaults to application/x-www-form-urlencoded. For JSON, always pair -d with an explicit -H "Content-Type: application/json".
# Form-encoded body (default when using -d)
curl -X POST https://api.example.com/login -d "username=alice&password=secret"
# JSON body — always include Content-Type
curl -X POST https://api.example.com/users -H "Content-Type: application/json" -d '{"name": "Alice", "email": "alice@example.com"}'
# JSON from a local file
curl -X POST https://api.example.com/users -H "Content-Type: application/json" -d @payload.json
# Binary file upload — use --data-binary to preserve the file exactly
curl -X POST https://api.example.com/upload -H "Content-Type: application/octet-stream" --data-binary @report.pdf
# Multipart form data (file + fields together)
curl -X POST https://api.example.com/upload -F "file=@photo.jpg" -F "caption=Profile photo"The difference between -d and --data-binary matters for binary content: -d strips newlines, which corrupts binary files. Use --data-binary whenever you are sending anything that is not plain text.
Authentication: Bearer tokens, Basic auth, and API keys
Most APIs require authentication on every request. cURL supports all three common patterns: Bearer tokens sent in the Authorization header, HTTP Basic auth via the -u shorthand, and API keys passed as headers or query parameters.
# Bearer token — most common for OAuth2 / JWT APIs
curl https://api.example.com/me -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Use an environment variable to avoid exposing the token in shell history
curl https://api.example.com/me -H "Authorization: Bearer $ACCESS_TOKEN"
# HTTP Basic auth with -u (cURL encodes it as Base64 automatically)
curl https://api.example.com/admin -u alice:mysecretpassword
# Basic auth without exposing the password in the command — cURL will prompt
curl https://api.example.com/admin -u alice
# API key in a custom header (common with services like Stripe, OpenAI)
curl https://api.openai.com/v1/models -H "Authorization: Bearer $OPENAI_API_KEY"
# API key as a query parameter (less secure — avoid where possible)
curl "https://api.example.com/data?api_key=$API_KEY"Prefer environment variables over hardcoded tokens. Commands are often logged to shell history, CI logs, or pasted into chat tools, and a token embedded directly in the command is easy to leak accidentally.
Following redirects, verbosity, and silent mode
By default, cURL does not follow HTTP redirects — it returns the 301 or 302 response as-is. The -L flag tells it to follow redirects until it reaches the final destination. Three verbosity flags control how much you see during the request.
# Follow redirects
curl -L https://short.url/abc123
# -v (verbose): shows request headers, response headers, and TLS handshake
# Useful for debugging exactly what is being sent and received
curl -v https://api.example.com/users
# -i (include): shows response headers above the body, without all the noise of -v
# Best for checking status codes and response headers quickly
curl -i https://api.example.com/users
# -s (silent): suppresses the progress meter and error messages
# Use when piping output to jq or another tool
curl -s https://api.example.com/users | jq .
# Combine -s and -S: silent but still show errors if the request fails
curl -sS https://api.example.com/users | jq .The -v output can be overwhelming at first, but it is the definitive answer to questions like "is my Authorization header actually being sent?" and "which TLS certificate is the server presenting?" Once you learn to read it, it becomes the fastest debug tool available.
Output control: saving files and extracting response codes
By default, cURL writes the response body to stdout. Three flags change that behaviour: -o saves to a named file, -O saves using the filename from the URL, and -w lets you print specific metadata about the response such as the HTTP status code or total time.
# Save response body to a specific file
curl -o response.json https://api.example.com/users
# Save using the filename from the URL path
curl -O https://files.example.com/reports/monthly.pdf
# Print only the HTTP status code — body goes to /dev/null
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health
# Print status code plus response time
curl -s -o /dev/null -w "Status: %{http_code} Time: %{time_total}s" https://api.example.com/users
# Write the body to a file AND still see the status code
curl -s -o response.json -w "%{http_code}" https://api.example.com/usersThe -w flag accepts a format string with over 40 available variables including%{http_code}, %{time_total}, %{size_download}, and%{url_effective} (the final URL after any redirects). Run man curl and search for -w to see the full list.
Timeouts and retries
In scripts and CI pipelines, a hung cURL request can block a job indefinitely. Three flags give you control over how long cURL will wait and whether it will try again automatically on failure.
# --connect-timeout: how long to wait to establish the TCP connection (seconds)
curl --connect-timeout 5 https://api.example.com/users
# --max-time: total time limit for the entire request including transfer (seconds)
curl --max-time 30 https://api.example.com/large-export
# Retry up to 3 times on transient failures (network errors, 5xx)
curl --retry 3 https://api.example.com/users
# Retry with a delay between attempts (seconds)
curl --retry 3 --retry-delay 2 https://api.example.com/users
# All three combined — a robust production-ready call
curl --connect-timeout 5 --max-time 30 --retry 3 --retry-delay 2 -s https://api.example.com/usersNote that --retry only retries on transient errors (connection failures, timeouts, and 5xx responses when combined with --retry-all-errors). It will not retry a 401 or a 404 — those are deterministic failures that retrying will not fix.
HTTPS and certificate handling
cURL verifies TLS certificates by default, which is the correct behaviour for production. Three flags cover the situations where you need to adjust that: skipping verification in local development, trusting a custom CA bundle for internal services, and providing a client certificate for mutual TLS.
# -k / --insecure: skip certificate verification
# ONLY use this in local development against self-signed certs — never in production
curl -k https://localhost:8443/api/health
# --cacert: trust a specific CA certificate file (for internal PKI)
curl --cacert /path/to/internal-ca.crt https://internal-api.company.com/data
# --cert: provide a client certificate for mutual TLS (mTLS)
curl --cert /path/to/client.crt --key /path/to/client.key https://api.example.com/secure
# Combined: client cert with a custom CA
curl --cacert /path/to/ca.crt --cert /path/to/client.crt --key /path/to/client.key https://internal-api.company.com/secureIf you are sharing a cURL command in a ticket or doc and you have used -k, call that out explicitly. A reviewer who sees -k without context cannot tell whether it is intentional or a mistake that would cause a certificate error to go undetected in production.
Useful combinations for real workflows
Individual flags are easy to learn in isolation, but the value of cURL comes from composing them for specific tasks. Here are three patterns that appear constantly in real API work.
Health check one-liner
# Returns the HTTP status code only — perfect for scripts and monitoring
curl -s -o /dev/null -w "%{http_code}" --max-time 5 https://api.example.com/healthDebug a broken endpoint
# -v shows the full exchange: TLS handshake, request headers sent, response headers
# Pipe body through jq to pretty-print JSON while still seeing all headers
curl -v -H "Authorization: Bearer $ACCESS_TOKEN" -H "Accept: application/json" https://api.example.com/users/42 2>&1 | tee debug.log | jq .Measure response time
# Full timing breakdown: DNS, connect, TLS, TTFB, and total
curl -s -o /dev/null -w "DNS: %{time_namelookup}s Connect: %{time_connect}s TLS: %{time_appconnect}s TTFB: %{time_starttransfer}s Total: %{time_total}s
" https://api.example.com/usersThe timing breakdown is particularly useful when diagnosing slow endpoints — it tells you immediately whether the delay is in DNS resolution, TLS negotiation, or the server actually processing the request.
When to generate cURL vs convert it to code
Two common workflows pull in opposite directions: building a cURL command from scratch, and turning an existing cURL command into code that runs in your application.
When you are exploring an API, reproducing a bug, or writing a command to share in a ticket, you want to generate the cURL command correctly the first time without memorizing flag syntax for every edge case. The cURL Generator lets you fill in the method, URL, headers, authentication type, and request body through a form and gives you a copy-paste-ready command with all the flags in the right order.
The opposite situation is when you have a cURL command — copied from API documentation, exported from browser DevTools via "Copy as cURL", or received from a colleague — and you need to translate it into Python, JavaScript, Go, or another language for use in your application. Doing that translation by hand means knowing each language's HTTP client API and getting the header serialization, body encoding, and authentication exactly right.
The cURL Converter handles this automatically — paste in any cURL command and get idiomatic code in the language of your choice, with the correct library imports and request construction. Both tools complement the cheat sheet above: the cheat sheet tells you what the flags mean, the generator and converter handle the mechanical work of building and translating commands correctly.