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

Adding Headers

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 @-

Form Data

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

Show Headers

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

Extract Specific Info

 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~cm/oa".nxUcn-suetercirltm-r-eActgi6em0neto:utMy1C0LI/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

FlagPurpose
-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.