curl is the universal HTTP client. Every developer should know it well—for debugging, testing, and automation.

Basic Requests

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# GET (default)
curl https://api.example.com/users

# POST with data
curl -X POST https://api.example.com/users \
  -d '{"name":"alice"}'

# With headers
curl -H "Content-Type: application/json" \
  -H "Authorization: Bearer token123" \
  https://api.example.com/users

JSON APIs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# POST JSON (sets Content-Type automatically)
curl -X POST https://api.example.com/users \
  --json '{"name":"alice","email":"alice@example.com"}'

# Or explicitly
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name":"alice"}'

# Pretty print response
curl -s https://api.example.com/users | jq .

# From file
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d @payload.json

HTTP Methods

1
2
3
4
5
6
7
curl -X GET https://api.example.com/users/1
curl -X POST https://api.example.com/users -d '...'
curl -X PUT https://api.example.com/users/1 -d '...'
curl -X PATCH https://api.example.com/users/1 -d '...'
curl -X DELETE https://api.example.com/users/1
curl -X HEAD https://api.example.com/users  # Headers only
curl -X OPTIONS https://api.example.com/users  # CORS preflight

Authentication

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Bearer token
curl -H "Authorization: Bearer eyJhbGc..." \
  https://api.example.com/me

# Basic auth
curl -u username:password https://api.example.com/users
# Or
curl -H "Authorization: Basic $(echo -n 'user:pass' | base64)" \
  https://api.example.com/users

# API key in header
curl -H "X-API-Key: secret123" https://api.example.com/data

# API key in query
curl "https://api.example.com/data?api_key=secret123"

Response Inspection

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# Show headers
curl -I https://api.example.com/users  # HEAD request
curl -i https://api.example.com/users  # Include headers with body

# Verbose (see full request/response)
curl -v https://api.example.com/users

# Just status code
curl -s -o /dev/null -w "%{http_code}" https://api.example.com/users

# Multiple stats
curl -s -o /dev/null -w "code: %{http_code}\ntime: %{time_total}s\nsize: %{size_download} bytes\n" \
  https://api.example.com/users

File Uploads

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# Form upload
curl -X POST https://api.example.com/upload \
  -F "file=@document.pdf"

# Multiple files
curl -X POST https://api.example.com/upload \
  -F "file1=@doc1.pdf" \
  -F "file2=@doc2.pdf"

# With additional form fields
curl -X POST https://api.example.com/upload \
  -F "file=@photo.jpg" \
  -F "description=Profile photo" \
  -F "public=true"

# Binary data
curl -X POST https://api.example.com/upload \
  -H "Content-Type: application/octet-stream" \
  --data-binary @file.bin

Handling Redirects

1
2
3
4
5
6
7
8
# Follow redirects
curl -L https://example.com/shortened-url

# Show redirect chain
curl -L -v https://example.com/shortened-url 2>&1 | grep "< location"

# Limit redirects
curl -L --max-redirs 3 https://example.com/url

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/

# Max time for entire operation
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 errors
curl --retry 3 --retry-all-errors https://api.example.com/

Saving Output

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Save to file
curl -o response.json https://api.example.com/users

# Use remote filename
curl -O https://example.com/file.zip

# Save headers separately
curl -D headers.txt -o body.json https://api.example.com/users

# Append to file
curl https://api.example.com/users >> all_responses.json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 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=admin&pass=secret"

# Use saved cookies
curl -b cookies.txt https://api.example.com/dashboard

# Both save and send
curl -b cookies.txt -c cookies.txt https://api.example.com/

Testing Webhooks

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# Simulate GitHub webhook
curl -X POST http://localhost:3000/webhook \
  -H "Content-Type: application/json" \
  -H "X-GitHub-Event: push" \
  -H "X-Hub-Signature-256: sha256=..." \
  -d @github-payload.json

# Stripe webhook
curl -X POST http://localhost:3000/stripe/webhook \
  -H "Content-Type: application/json" \
  -H "Stripe-Signature: t=...,v1=..." \
  -d @stripe-event.json

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 bundle
curl --cacert /path/to/ca-bundle.crt https://api.example.com/

# Client certificate
curl --cert client.crt --key client.key https://mtls.example.com/

Proxy Configuration

1
2
3
4
5
6
7
8
# HTTP proxy
curl -x http://proxy:8080 https://api.example.com/

# SOCKS5 proxy
curl --socks5 localhost:1080 https://api.example.com/

# No proxy for specific hosts
curl --noproxy "localhost,*.internal" https://api.example.com/

Performance Testing

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# Time breakdown
curl -s -o /dev/null -w "\
   namelookup: %{time_namelookup}s\n\
      connect: %{time_connect}s\n\
   appconnect: %{time_appconnect}s\n\
  pretransfer: %{time_pretransfer}s\n\
     redirect: %{time_redirect}s\n\
starttransfer: %{time_starttransfer}s\n\
        total: %{time_total}s\n" \
  https://api.example.com/

# Loop for load testing (basic)
for i in {1..100}; do
  curl -s -o /dev/null -w "%{http_code} %{time_total}\n" \
    https://api.example.com/
done

Config Files

Create ~/.curlrc for defaults:

####----AlDmSsUuloeahhsswcfxooeeaaa-wwrrytut--silieeaaotmrrggfnerreeotoonnli3rrttlm0soe"womuyrtceudrilr/e1c.t0s"

Practical Scripts

Health Check

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash
URL="https://api.example.com/health"
STATUS=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$URL")

if [ "$STATUS" = "200" ]; then
  echo "OK"
  exit 0
else
  echo "FAIL: HTTP $STATUS"
  exit 1
fi

API Test Suite

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
BASE="https://api.example.com"
TOKEN="Bearer $(cat .token)"

# Test endpoints
test_endpoint() {
  local method=$1 path=$2 expected=$3
  status=$(curl -s -o /dev/null -w "%{http_code}" \
    -X "$method" -H "Authorization: $TOKEN" "$BASE$path")
  
  if [ "$status" = "$expected" ]; then
    echo "✓ $method $path"
  else
    echo "✗ $method $path (got $status, expected $expected)"
  fi
}

test_endpoint GET /users 200
test_endpoint GET /users/1 200
test_endpoint GET /users/999 404
test_endpoint POST /users 401  # No body
test_endpoint DELETE /admin 403

Download with Progress

1
2
curl -L -# -o large-file.zip \
  https://example.com/large-file.zip

Common Options Reference

OptionPurpose
-X METHODHTTP method
-H "Header: value"Add header
-d "data"POST data
-F "field=value"Form data
-o fileOutput to file
-OUse remote filename
-LFollow redirects
-vVerbose
-sSilent
-iInclude headers
-IHeaders only
-u user:passBasic auth
-b cookiesSend cookies
-c fileSave cookies
-kInsecure (skip TLS verify)
--max-time NTimeout
--retry NRetry count

curl is the debugging tool you’ll use for the rest of your career. Master it.