Every API documentation page has the same thing: a cURL example. It’s the lingua franca of HTTP requests. Whether you’re testing a new endpoint, debugging a webhook, or demonstrating an API to a colleague, cURL is the tool you reach for first.
The problem is that cURL has over 380 command-line options. Nobody knows all of them. But there are about 15 that cover 95% of real-world use cases. Here’s the reference I wish I’d had when I started.
The Basics
Simple GET Request
curl https://api.example.com/users
That’s it. No flags needed for a basic GET. cURL outputs the response body to stdout.
See Response Headers
# Headers only (HEAD request)
curl -I https://api.example.com/users
# Headers AND body
curl -i https://api.example.com/users
# Verbose mode — see the full request/response exchange
curl -v https://api.example.com/users
The -v (verbose) flag is your best debugging tool. It shows the DNS resolution, TCP connection, TLS handshake, request headers, and response headers — everything you need to diagnose connection issues.
POST Request with JSON Body
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
Breaking it down:
-X POST— sets the HTTP method-H— adds a request header-d— sends data in the request body (also implies POST if no-Xis specified)
PUT, PATCH, DELETE
# Update a resource
curl -X PUT https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Updated"}'
# Partial update
curl -X PATCH https://api.example.com/users/123 \
-H "Content-Type: application/json" \
-d '{"name": "Alice Patched"}'
# Delete a resource
curl -X DELETE https://api.example.com/users/123
Need this in your language? Our cURL to Code Converter transforms any cURL command into JavaScript (fetch), Python (requests), Go, PHP, and Node.js — instantly.
Authentication
Bearer Token
curl https://api.example.com/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Basic Auth
# Using -u flag (cURL encodes to Base64 automatically)
curl -u username:password https://api.example.com/protected
# Equivalent manual header
curl -H "Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=" https://api.example.com/protected
API Key in Header
curl https://api.example.com/data \
-H "X-API-Key: your-api-key-here"
API Key in Query String
curl "https://api.example.com/data?api_key=your-api-key-here"
Note: Always quote URLs with query parameters. The & character has special meaning in the shell and will break your command if unquoted.
Working with Data
Send Form Data
# URL-encoded form (default for -d)
curl -X POST https://api.example.com/login \
-d "username=alice&password=secret123"
# Multipart form (for file uploads)
curl -X POST https://api.example.com/upload \
-F "file=@/path/to/document.pdf" \
-F "description=My document"
The -F flag sends multipart/form-data — required for file uploads. The @ prefix tells cURL to read the file contents.
Read Request Body from a File
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d @payload.json
The @ prefix with -d reads the data from a file. Extremely useful for large payloads or payloads you use repeatedly.
Save Response to a File
# Save output to file
curl -o response.json https://api.example.com/data
# Save with the server's filename (from Content-Disposition)
curl -O https://example.com/files/report.pdf
# Download silently (no progress bar)
curl -s -o output.json https://api.example.com/data
Debugging Requests
Verbose Output
curl -v https://api.example.com/users 2>&1 | head -30
The verbose output uses > for request data and < for response data:
> GET /users HTTP/2
> Host: api.example.com
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/2 200
< content-type: application/json
< x-ratelimit-remaining: 98
< x-ratelimit-limit: 100
Timing Information
curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" https://api.example.com/users
Output:
DNS: 0.023s
Connect: 0.045s
TLS: 0.112s
Total: 0.234s
This is invaluable for diagnosing slow API calls. If DNS is slow, check your resolver. If TLS is slow, the certificate chain might be too long. If the total time is much longer than TLS, the server is slow to respond.
Only Show HTTP Status Code
curl -o /dev/null -s -w "%{http_code}" https://api.example.com/health
Perfect for health checks and monitoring scripts.
Common Patterns
Follow Redirects
# Follow up to 10 redirects (default)
curl -L https://example.com/short-link
# Follow redirects and show each step
curl -L -v https://example.com/short-link
Without -L, cURL returns the 301/302 response instead of following the redirect. This catches people constantly.
Set a Timeout
# Connection timeout (10 seconds to establish connection)
curl --connect-timeout 10 https://api.example.com/data
# Total operation timeout (30 seconds including transfer)
curl --max-time 30 https://api.example.com/data
# Both (recommended for scripts)
curl --connect-timeout 10 --max-time 30 https://api.example.com/data
Always set timeouts in scripts. A cURL command without a timeout will hang indefinitely if the server stops responding.
Send Cookies
# Send a specific cookie
curl -b "session=abc123; theme=dark" https://example.com/dashboard
# Save cookies to a file
curl -c cookies.txt https://example.com/login
# Send cookies from a file
curl -b cookies.txt https://example.com/dashboard
Ignore SSL Certificate Errors
curl -k https://self-signed.example.com/api
The -k flag skips SSL verification. Use this only for local development or testing with self-signed certificates. Never use it in production scripts — it defeats the purpose of TLS.
Custom User-Agent
curl -A "MyApp/1.0" https://api.example.com/data
# Some APIs require a specific user-agent
curl -A "Mozilla/5.0 (compatible; MyBot/1.0)" https://example.com/robots.txt
Converting cURL to Code
Every developer eventually needs to turn a cURL command into actual code. Here’s what the same request looks like across languages:
cURL:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer token123" \
-d '{"name": "Alice", "email": "alice@example.com"}'
JavaScript (fetch):
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
},
body: JSON.stringify({
name: 'Alice',
email: 'alice@example.com',
}),
});
Python (requests):
import requests
response = requests.post(
'https://api.example.com/users',
headers={
'Content-Type': 'application/json',
'Authorization': 'Bearer token123',
},
json={
'name': 'Alice',
'email': 'alice@example.com',
},
)
Go:
payload := strings.NewReader(`{"name": "Alice", "email": "alice@example.com"}`)
req, err := http.NewRequest("POST", "https://api.example.com/users", payload)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer token123")
client := &http.Client{}
resp, err := client.Do(req)
Converting manually is tedious and error-prone. The cURL to Code Converter handles edge cases like multipart bodies, special characters in headers, and authentication flags automatically.
cURL in Scripts: Best Practices
Always Quote Variables
# WRONG — breaks if TOKEN contains special characters
curl -H "Authorization: Bearer $TOKEN" https://api.example.com/data
# CORRECT
curl -H "Authorization: Bearer ${TOKEN}" https://api.example.com/data
Check the Exit Code
if curl -s -f -o /dev/null https://api.example.com/health; then
echo "API is healthy"
else
echo "API is down (exit code: $?)"
fi
The -f flag makes cURL return a non-zero exit code on HTTP errors (4xx, 5xx), which is essential for script error handling.
Retry Failed Requests
curl --retry 3 --retry-delay 5 --retry-max-time 60 https://api.example.com/data
cURL has built-in retry logic. Use it instead of writing a bash retry loop.
Quick Reference
| Flag | Purpose | Example |
|---|---|---|
-X | Set HTTP method | -X POST |
-H | Add header | -H "Content-Type: application/json" |
-d | Send body data | -d '{"key": "value"}' |
-F | Send form/file | -F "file=@photo.jpg" |
-u | Basic auth | -u user:pass |
-i | Show response headers | |
-v | Verbose output | |
-s | Silent (no progress) | |
-o | Save to file | -o output.json |
-L | Follow redirects | |
-k | Skip SSL verify | |
-b | Send cookies | -b "session=abc" |
-w | Custom output format | -w "%{http_code}" |
Further Reading
- HTTP Status Codes: The Complete Guide
- API Rate Limiting: How It Works
- Webhooks Explained: Building Reliable Integrations
Got a cURL command you need in another language? The cURL to Code Converter handles JavaScript, Python, Go, PHP, and Node.js instantly. And if you’re debugging the response headers, run them through the HTTP Header Analyzer for a security assessment.