curl is the fastest way to test an API without opening Postman, writing a script, or spinning up a tool. It's available everywhere — Linux, macOS, Windows — and once you know a handful of flags, you can test virtually any HTTP endpoint from your terminal.
Basic GET Request
The simplest curl command: fetch a URL.
curl https://api.github.com/users/octocat
This sends a GET request and prints the response body. To also see response headers:
curl -i https://api.github.com/users/octocat
-i (include) shows HTTP status and headers before the body. -I (uppercase) fetches only headers (HEAD request) — useful for checking if an endpoint is alive without downloading the body.
Pretty-Printing JSON
curl outputs raw JSON with no formatting. Pipe it through Python's json module:
curl -s https://api.github.com/users/octocat | python3 -m json.tool
-s (silent) suppresses the progress meter. Or use jq if installed:
curl -s https://api.github.com/users/octocat | jq '.name, .public_repos'
POST Request with JSON Body
Sending data to an API requires the method flag and a body.
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "Alice", "email": "alice@example.com"}'
Breaking this down:
-
-X POSTsets the HTTP method -
-Hadds a header (can be used multiple times) -
-dprovides the request body
For larger payloads, read from a file:
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d @user.json
The @ prefix tells curl to read the content from the file user.json.
Authentication
Bearer Token
curl -H "Authorization: Bearer eyJhbGc..." https://api.example.com/protected
API Key in Header
curl -H "X-API-Key: your_api_key_here" https://api.example.com/data
Basic Auth
curl -u username:password https://api.example.com/admin
# or let curl prompt for password:
curl -u username https://api.example.com/admin
-u handles base64 encoding automatically.
PUT and PATCH Requests
# Full update (PUT)
curl -X PUT https://api.example.com/users/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Alice Smith", "email": "alice@example.com"}'
# Partial update (PATCH)
curl -X PATCH https://api.example.com/users/42 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"email": "newalice@example.com"}'
DELETE Request
curl -X DELETE https://api.example.com/users/42 \
-H "Authorization: Bearer $TOKEN"
Useful Debugging Flags
-v (verbose)
Shows everything: request headers, response headers, TLS handshake, redirect chain.
curl -v https://api.example.com/users
Look for < prefixed lines (response headers) and > prefixed lines (request headers).
-w (write-out)
Extracts specific metrics after the request completes.
curl -s -o /dev/null -w "Status: %{http_code}\nTime: %{time_total}s\n" https://api.example.com/users
Common write-out variables:
-
%{http_code}— HTTP status code -
%{time_total}— total time in seconds -
%{size_download}— bytes downloaded -
%{url_effective}— final URL after redirects
--max-time
Prevents hanging on slow endpoints:
curl --max-time 5 https://api.example.com/slow-endpoint
Handling Redirects
By default curl doesn't follow redirects. Add -L:
curl -L https://api.example.com/redirect
Saving Response to File
curl -o response.json https://api.example.com/data
-o writes to a named file. -O uses the server's filename.
Sending Form Data
For application/x-www-form-urlencoded (traditional HTML forms):
curl -X POST https://api.example.com/login \
-d "username=alice&password=secret"
For multipart form data (file uploads):
curl -X POST https://api.example.com/upload \
-F "file=@photo.jpg" \
-F "description=Profile photo"
Query Parameters
Encode them directly in the URL or use --data-urlencode for values with special characters:
curl "https://api.example.com/search?q=hello+world&limit=10"
# Safe encoding for complex values:
curl -G https://api.example.com/search \
--data-urlencode "q=hello world & more" \
--data-urlencode "limit=10"
A Real-World Example: GitHub API
# List your repos (replace TOKEN)
curl -s \
-H "Authorization: Bearer ghp_yourtoken" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/user/repos?per_page=5&sort=updated" \
| python3 -m json.tool
# Create an issue
curl -s -X POST \
-H "Authorization: Bearer ghp_yourtoken" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/owner/repo/issues" \
-d '{"title": "Bug: login fails", "body": "Steps to reproduce..."}'
Quick Reference
| Task | Flag |
|---|---|
| Set HTTP method |
-X POST / -X PUT / -X DELETE
|
| Add header | -H "Key: Value" |
| Send JSON body | -d '{"key":"val"}' |
| Read body from file | -d @file.json |
| Bearer auth | -H "Authorization: Bearer TOKEN" |
| Basic auth | -u user:pass |
| Follow redirects | -L |
| Show headers in output | -i |
| Verbose debug | -v |
| Silent (no progress) | -s |
| Save to file | -o filename |
| Timeout | --max-time 10 |
curl covers 90% of API testing scenarios directly from the terminal. Once you internalize these flags, you'll reach for it instinctively before opening any GUI tool.
Level Up Your Dev Workflow
Found this useful? Explore DevPlaybook — cheat sheets, tool comparisons, and hands-on guides for modern developers.
🛒 Get the DevToolkit Starter Kit on Gumroad — 40+ browser-based dev tools, source code + deployment guide included.
Top comments (0)