Every developer ends up using curl. It’s installed everywhere, works with any API, and once you learn the patterns, it’s faster than any GUI tool.

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"}'

# Other methods
curl -X PUT ...
curl -X DELETE ...
curl -X PATCH ...

Headers

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Set content type
curl -H "Content-Type: application/json" ...

# Auth header
curl -H "Authorization: Bearer TOKEN" ...

# Multiple headers
curl -H "Content-Type: application/json" \
     -H "Authorization: Bearer TOKEN" \
     -H "X-Custom-Header: value" ...

JSON Data

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 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 @data.json

# Pretty output (pipe to jq)
curl -s https://api.example.com/users | jq

Response Info

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Show response headers
curl -i https://api.example.com/users

# Only headers (no body)
curl -I https://api.example.com/users

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

# Timing info
curl -w "Time: %{time_total}s\n" -o /dev/null -s https://api.example.com

Authentication

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# Basic auth
curl -u username:password https://api.example.com

# Bearer token
curl -H "Authorization: Bearer eyJ..." https://api.example.com

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

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

Form Data

1
2
3
4
5
6
7
8
# URL-encoded form
curl -X POST https://example.com/login \
  -d "username=alice&password=secret"

# Multipart form (file upload)
curl -X POST https://example.com/upload \
  -F "file=@photo.jpg" \
  -F "description=My photo"

Following Redirects

1
2
3
4
5
# Follow redirects (3xx)
curl -L https://example.com/redirect

# Show redirect chain
curl -L -v https://example.com/redirect 2>&1 | grep "< HTTP\|< Location"

SSL/TLS

1
2
3
4
5
6
7
8
# Ignore SSL errors (dev only!)
curl -k https://self-signed.example.com

# Use specific cert
curl --cacert /path/to/ca.crt https://api.example.com

# Client cert authentication
curl --cert client.crt --key client.key https://api.example.com

Timeouts

1
2
3
4
5
6
7
8
# Connection timeout (seconds)
curl --connect-timeout 5 https://api.example.com

# Max time for entire operation
curl --max-time 30 https://api.example.com

# Both
curl --connect-timeout 5 --max-time 30 https://api.example.com

Debugging

1
2
3
4
5
6
7
8
# Verbose output
curl -v https://api.example.com

# Even more verbose (includes SSL handshake)
curl -vv https://api.example.com

# Trace everything to file
curl --trace trace.log https://api.example.com

Saving Output

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

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

# Silent mode (no progress)
curl -s https://api.example.com

Cookies

1
2
3
4
5
6
7
8
# Send cookie
curl -b "session=abc123" https://example.com

# Save cookies to file
curl -c cookies.txt https://example.com/login -d "user=alice"

# Send cookies from file
curl -b cookies.txt https://example.com/dashboard

Retry Logic

1
2
3
4
5
6
7
8
# Retry on failure
curl --retry 3 https://api.example.com

# Retry with delay
curl --retry 3 --retry-delay 2 https://api.example.com

# Retry on specific errors
curl --retry 3 --retry-connrefused https://api.example.com

Useful Aliases

Add to your .bashrc:

1
2
3
4
5
6
7
8
# JSON POST
alias curlj='curl -H "Content-Type: application/json"'

# Pretty JSON output
alias curljq='curl -s | jq'

# Show just status code
alias curlstatus='curl -s -o /dev/null -w "%{http_code}\n"'

Real-World Examples

Test API endpoint:

1
2
curl -s -X GET "https://api.example.com/users/123" \
  -H "Authorization: Bearer $TOKEN" | jq

Create resource:

1
2
3
4
curl -s -X POST "https://api.example.com/users" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name":"Alice","email":"alice@example.com"}' | jq

Upload file:

1
2
3
4
curl -X POST "https://api.example.com/upload" \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@report.pdf" \
  -F "folder=documents"

Health check script:

1
2
3
4
5
6
#!/bin/bash
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.example.com/health)
if [ "$STATUS" != "200" ]; then
    echo "API is down! Status: $STATUS"
    exit 1
fi

Measure response time:

1
2
3
4
5
6
7
curl -s -o /dev/null -w "
DNS:        %{time_namelookup}s
Connect:    %{time_connect}s
TLS:        %{time_appconnect}s
Start:      %{time_starttransfer}s
Total:      %{time_total}s
" https://api.example.com

Download with progress:

1
curl -# -O https://example.com/large-file.zip

Quick Reference

TaskCommand
GET requestcurl URL
POST JSONcurl -X POST -H "Content-Type: application/json" -d '{}' URL
Auth headercurl -H "Authorization: Bearer TOKEN" URL
Basic authcurl -u user:pass URL
Show headerscurl -i URL
Follow redirectscurl -L URL
Silent + jqcurl -s URL | jq
Status code onlycurl -s -o /dev/null -w "%{http_code}" URL
Upload filecurl -F "file=@path" URL
Save responsecurl -o file.json URL

curl does one thing well: talk HTTP. Master these patterns and you’ll debug APIs faster than any GUI tool.