Test HTTP Endpoints with curl and httpie
Learn to test HTTP APIs from the command line using curl flags and HTTPie syntax, covering GET/POST, JSON bodies, auth headers, and mutual TLS.
Before you start
- ▸Terminal access with sudo privileges for package installation
- ▸Python 3.8+ and pipx installed if using the pipx install method for HTTPie
- ▸A reachable HTTP endpoint to test against (httpbin.org works over the public internet)
Two tools dominate HTTP testing on the command line: curl, the Swiss Army knife that ships on almost every system, and HTTPie, a human-friendly alternative with sane defaults for JSON and authentication. Knowing both lets you move fast when debugging APIs, writing scripts, or tracing down a misbehaving service.
Installing the Tools
curl
curl is almost certainly already installed. If not:
# Debian/Ubuntu
sudo apt install curl
# Fedora/RHEL/Rocky
sudo dnf install curl
# Arch
sudo pacman -S curl
HTTPie
Install the maintained httpie package. Avoid the outdated system packages on some distros — the pip or pipx route gives you the current version.
# Recommended: pipx (isolated, no dependency conflicts)
pipx install httpie
# Debian/Ubuntu system package (may be older)
sudo apt install httpie
# Fedora/RHEL
sudo dnf install httpie
# Arch
sudo pacman -S httpie
Basic GET Requests
curl
By default curl sends a GET and writes the response body to stdout. Useful flags to know immediately:
- -s — silent (suppress progress meter)
- -o /dev/null — discard body
- -w — write-out format (great for status codes)
- -v — verbose: shows request and response headers
- -I — HEAD request only (headers, no body)
# Fetch and print the response body
curl https://httpbin.org/get
# Show only the HTTP status code
curl -s -o /dev/null -w "%{http_code}\n" https://httpbin.org/get
# Print response headers and body
curl -v https://httpbin.org/get
# HEAD request — headers only
curl -I https://httpbin.org/get
HTTPie
HTTPie prints colorized, formatted output by default. The command structure is http [METHOD] URL [items...]. If you omit the method it defaults to GET (or POST when a body is present).
http https://httpbin.org/get
# Print only the response headers
http --headers https://httpbin.org/get
# Print only the response body
http --body https://httpbin.org/get
Sending JSON
curl
You must set the Content-Type header manually and provide the JSON body as a string or file.
# Inline JSON body
curl -s -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d '{"username": "alice", "role": "admin"}'
# Read JSON from a file
curl -s -X POST https://httpbin.org/post \
-H "Content-Type: application/json" \
-d @payload.json
HTTPie
HTTPie sets Content-Type: application/json automatically when you pass key-value items with := (raw JSON value) or = (string value). No quoting gymnastics needed.
# String and integer values — HTTPie builds the JSON object
http POST https://httpbin.org/post \
username=alice \
role=admin \
active:=true \
score:=42
# Send a pre-built JSON file
http POST https://httpbin.org/post < payload.json
Setting Custom Headers
curl
Pass headers with -H "Name: value". Repeat the flag for multiple headers.
curl -s https://httpbin.org/headers \
-H "X-Request-ID: abc123" \
-H "Accept: application/json"
HTTPie
Headers use the Name:value item syntax (colon with no space before it, space after is optional).
http https://httpbin.org/headers \
X-Request-ID:abc123 \
Accept:application/json
Authentication
Bearer Tokens
# curl
curl -s https://httpbin.org/bearer \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9..."
# HTTPie
http https://httpbin.org/bearer \
"Authorization:Bearer eyJhbGciOiJSUzI1NiJ9..."
HTTP Basic Auth
# curl — prompts for password if you omit it after the colon
curl -u alice:secretpass https://httpbin.org/basic-auth/alice/secretpass
# HTTPie
http -a alice:secretpass https://httpbin.org/basic-auth/alice/secretpass
API Key in a Header
# curl
curl -s https://api.example.com/data \
-H "X-API-Key: my-secret-key-here"
# HTTPie
http https://api.example.com/data \
X-API-Key:my-secret-key-here
Mutual TLS (mTLS)
mTLS requires the client to present a certificate alongside verifying the server's certificate. You need a client certificate and its private key. If they are in separate files:
curl with mTLS
# PEM cert + separate key
curl -s https://api.example.com/secure \
--cert client.crt \
--key client.key \
--cacert ca.crt
# PKCS#12 bundle (.p12 / .pfx) — curl prompts for the import password
curl -s https://api.example.com/secure \
--cert-type P12 \
--cert client.p12 \
--cacert ca.crt
HTTPie with mTLS
http https://api.example.com/secure \
--cert client.crt \
--cert-key client.key \
--verify ca.crt
If the server uses a self-signed cert and you just want to skip verification during development (never in production), use curl -k or http --verify=no. Both will warn you — deliberately.
Useful Productivity Flags
Follow Redirects and Time Out
# curl: follow up to 10 redirects, 5-second connect timeout, 30-second max
curl -L --max-redirs 10 --connect-timeout 5 --max-time 30 https://example.com
# HTTPie follows redirects by default; set timeouts
http --follow --timeout=30 https://example.com
Save Output to a File
# curl
curl -s -o response.json https://httpbin.org/get
# HTTPie
http --output response.json https://httpbin.org/get
Pretty-print JSON with curl
curl does not format JSON. Pipe to jq (install separately) for readable output.
curl -s https://httpbin.org/get | jq .
Verifying Your Requests Work
Use httpbin.org as a free echo server. The /anything endpoint reflects back exactly what you sent:
# curl — confirm headers and body were received correctly
curl -s -X POST https://httpbin.org/anything \
-H "Content-Type: application/json" \
-H "X-Trace-ID: 999" \
-d '{"test": true}' | jq .headers,.json
# HTTPie equivalent
http POST https://httpbin.org/anything \
X-Trace-ID:999 \
test:=true
The response will echo the headers and JSON body your client sent. If you see your custom header and parsed JSON in the output, the request was built correctly.
Troubleshooting
- SSL certificate errors — Check the server's cert chain with
curl -vand look for SSL certificate problem. Provide the CA cert with--cacertrather than disabling verification. - Connection refused — The service is not listening on that port. Confirm with
ss -tlnpon the server side. - 401 Unauthorized — Token or credentials are wrong, or the header name is misspelled. Use
-v/ HTTPie's default verbose output to confirm the header reached the server. - HTTPie command not found after pipx install — Run
pipx ensurepathand open a new shell. The~/.local/bindirectory needs to be on yourPATH. - curl percent-encoding issues in URLs — Use
--data-urlencodefor form fields or wrap the URL in single quotes when it contains special shell characters.
Frequently asked questions
- When should I use curl instead of HTTPie?
- Use curl in scripts, CI pipelines, and any environment where you cannot install Python packages. HTTPie is better for interactive API exploration thanks to its readable, colorized output and simpler JSON syntax.
- How do I send a PUT or DELETE request?
- With curl, add -X PUT or -X DELETE before the URL. With HTTPie, replace the GET/POST keyword: http PUT https://api.example.com/items/1 or http DELETE https://api.example.com/items/1.
- How do I pass query string parameters cleanly?
- In curl use --data-urlencode with GET: curl -G https://httpbin.org/get --data-urlencode 'q=hello world'. In HTTPie, use the == operator: http https://httpbin.org/get q=='hello world'.
- Can curl and HTTPie follow HTTP redirects automatically?
- curl requires the -L flag to follow redirects. HTTPie follows redirects by default; disable with --no-follow if you need to inspect the 3xx response itself.
- How do I store and reuse sessions or cookies?
- With curl, use --cookie-jar cookies.txt to save cookies and --cookie cookies.txt to send them back. HTTPie has built-in named sessions: http --session=./session.json POST https://api.example.com/login.
Related guides
Build a Mesh VPN with Nebula
Build a fully self-hosted mesh VPN with Nebula: create a CA, sign node certs, configure lighthouses, enforce group-based firewall rules, and run as a systemd service.
Common Linux Network Ports Reference
Learn Linux port ranges, read /etc/services, find what's listening with ss and nmap, and apply solid firewall rules to expose or block the right ports.
How to Configure a Static IP on Linux
Configure a static IP on Linux using Netplan, NetworkManager (nmcli), or systemd-networkd across Ubuntu, Fedora, Debian, and Arch with verified steps.
Expose a Service with Cloudflare Tunnel
Expose local services to the internet without port-forwarding using Cloudflare Tunnel. Install cloudflared, create a named tunnel, configure ingress rules, and run as a systemd service.