curl is the universal HTTP client. It’s installed everywhere, works with any API, and once mastered, becomes your go-to tool for testing, debugging, and scripting HTTP interactions.
Basic Requests# 1
2
3
4
5
6
7
8
# GET (default)
curl https://api.example.com/users
# Explicit methods
curl -X POST https://api.example.com/users
curl -X PUT https://api.example.com/users/1
curl -X DELETE https://api.example.com/users/1
curl -X PATCH https://api.example.com/users/1
1
2
3
4
5
6
7
8
# Single header
curl -H "Authorization: Bearer token123" https://api.example.com/me
# Multiple headers
curl -H "Authorization: Bearer token123" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
https://api.example.com/users
Sending Data# JSON Body# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Inline JSON
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
# From file
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d @payload.json
# From stdin
echo '{"name": "Alice"}' | curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d @-
1
2
3
4
5
6
7
8
# URL-encoded (default for -d without Content-Type)
curl -X POST https://api.example.com/login \
-d "username=alice&password=secret"
# Multipart form (file uploads)
curl -X POST https://api.example.com/upload \
-F "file=@document.pdf" \
-F "description=My document"
Response Handling# 1
2
3
4
5
6
7
8
# Response headers only
curl -I https://api.example.com/health
# Headers + body
curl -i https://api.example.com/users
# Verbose (request + response headers)
curl -v https://api.example.com/users
Output Control# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Save to file
curl -o response.json https://api.example.com/users
# Save with remote filename
curl -O https://example.com/file.zip
# Silent (no progress bar)
curl -s https://api.example.com/users
# Silent but show errors
curl -sS https://api.example.com/users
# Only output body (suppress all else)
curl -s https://api.example.com/users | jq '.'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# HTTP status code only
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health
# Multiple variables
curl -s -o /dev/null -w "Status: %{http_code}\nTime: %{time_total}s\nSize: %{size_download} bytes\n" \
https://api.example.com/users
# Available variables
# %{http_code} - HTTP status code
# %{time_total} - Total time in seconds
# %{time_connect} - Time to establish connection
# %{time_starttransfer} - Time to first byte
# %{size_download} - Downloaded bytes
# %{url_effective} - Final URL after redirects
Authentication# 1
2
3
4
5
6
7
8
9
10
11
# Basic auth
curl -u username:password https://api.example.com/secure
# Bearer token
curl -H "Authorization: Bearer eyJhbG..." https://api.example.com/me
# API key in header
curl -H "X-API-Key: abc123" https://api.example.com/data
# API key in query string
curl "https://api.example.com/data?api_key=abc123"
Following Redirects# 1
2
3
4
5
6
7
8
# Follow redirects (disabled by default)
curl -L https://short.url/abc
# Limit redirect count
curl -L --max-redirs 5 https://example.com
# Show redirect chain
curl -L -v https://short.url/abc 2>& 1 | grep "< location"
Timeouts and Retries# 1
2
3
4
5
6
7
8
9
10
11
# Connection timeout (seconds)
curl --connect-timeout 5 https://api.example.com
# Total operation timeout
curl --max-time 30 https://api.example.com/slow-endpoint
# Retry on failure
curl --retry 3 --retry-delay 2 https://api.example.com
# Retry on specific HTTP codes
curl --retry 3 --retry-all-errors https://api.example.com
SSL/TLS Options# 1
2
3
4
5
6
7
8
# Skip certificate verification (development only!)
curl -k https://self-signed.example.com
# Use specific CA certificate
curl --cacert /path/to/ca.crt https://api.example.com
# Client certificate authentication
curl --cert client.crt --key client.key https://api.example.com
Cookies# 1
2
3
4
5
6
7
8
9
10
11
# Send cookies
curl -b "session=abc123; token=xyz" https://api.example.com
# Save cookies to file
curl -c cookies.txt https://api.example.com/login -d "user=alice&pass=secret"
# Load cookies from file
curl -b cookies.txt https://api.example.com/dashboard
# Both (maintain session)
curl -b cookies.txt -c cookies.txt https://api.example.com/action
Useful Patterns# Health Check Script# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
check_health() {
local url = $1
local status = $( curl -s -o /dev/null -w "%{http_code}" --max-time 5 " $url " )
if [ " $status " = "200" ] ; then
echo "β $url "
return 0
else
echo "β $url (HTTP $status )"
return 1
fi
}
check_health "https://api.example.com/health"
check_health "https://web.example.com"
API Testing# 1
2
3
4
5
6
7
8
9
10
# Create resource and capture ID
ID = $( curl -s -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Test User"}' | jq -r '.id' )
# Use captured ID
curl -s https://api.example.com/users/$ID | jq '.'
# Delete
curl -X DELETE https://api.example.com/users/$ID
Download with Progress# 1
2
3
4
5
# Show progress bar
curl -# -O https://example.com/large-file.zip
# Resume interrupted download
curl -C - -O https://example.com/large-file.zip
Parallel Requests# 1
2
3
4
5
6
7
8
# Using xargs
echo -e "url1\nurl2\nurl3" | xargs -P 4 -I {} curl -s {} -o /dev/null -w "{}: %{http_code}\n"
# Using curl's parallel feature (7.68+)
curl --parallel --parallel-immediate \
https://api1.example.com \
https://api2.example.com \
https://api3.example.com
Debugging# Trace All Details# 1
2
# Full trace including SSL handshake
curl -v --trace-ascii debug.txt https://api.example.com
Common Issues# 1
2
3
4
5
6
7
8
9
# DNS resolution problems
curl -v --resolve api.example.com:443:1.2.3.4 https://api.example.com
# Force IPv4 or IPv6
curl -4 https://api.example.com # IPv4 only
curl -6 https://api.example.com # IPv6 only
# Use specific interface
curl --interface eth0 https://api.example.com
Config File# Save common options in ~/.curlrc:
# - - s - - H ~ c m / o a " . n x U c n - s u e t e r c i r l t m - r - e A c t g i 6 e m 0 n e t o : u t M y 1 C 0 L I / 1 . 0 " Override for specific calls:
1
curl --no-config https://api.example.com # Ignore .curlrc
Shell Aliases# 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ~/.bashrc or ~/.zshrc
# JSON API calls
alias curljson = 'curl -s -H "Content-Type: application/json" -H "Accept: application/json"'
# Quick status check
curlstatus() { curl -s -o /dev/null -w "%{http_code}\n" " $1 " ; }
# Pretty JSON response
curlj() { curl -s " $@ " | jq '.' ; }
# Time a request
curltime() {
curl -s -o /dev/null -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n" " $1 "
}
Quick Reference# Flag Purpose -X METHODHTTP method -H "Header: Value"Add header -d "data"Send body data -F "field=value"Multipart form -o fileOutput to file -OSave with remote name -sSilent mode -vVerbose -iInclude response headers -IHeaders only (HEAD) -LFollow redirects -u user:passBasic auth -b cookiesSend cookies -c cookiesSave cookies -kSkip SSL verify --max-time NTimeout
curl does one thing extremely well: make HTTP requests. Combined with jq for JSON parsing and shell scripting, it becomes a complete API testing and automation toolkit. No GUI needed.
π¬ Get the Newsletter Weekly insights on DevOps, automation, and CLI mastery. No spam, unsubscribe anytime.