How to Use curl for API Testing
Learn how to test REST APIs using curl — GET, POST, headers, auth tokens, JSON payloads, debugging flags, and real-world examples.
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.
Free Newsletter
Level Up Your Dev Workflow
Get new tools, guides, and productivity tips delivered to your inbox.
Plus: grab the free Developer Productivity Checklist when you subscribe.
Found this guide useful? Check out our free developer tools.
Affiliate disclosure: Some links below are affiliate links — we may earn a small commission at no extra cost to you. Learn more.
Recommended Tools & Resources
DigitalOcean
$200 credit for new users. Simple, affordable cloud hosting for developers.
GitHub Student Pack
Free access to 100+ developer tools. Perfect for students and new devs.
Vercel
Deploy frontend apps instantly. Free tier is generous for side projects.
DevPlaybook Products
Boilerplates, scripts & AI toolkits to 10x your dev workflow.