curl API Patterns
curl recipes for API testing, debugging, and scripting.
Request Fundamentals
GET with headers and jq pipeline
curl -s -H "Accept: application/json" \
-H "Authorization: Bearer $TOKEN" \
https://api.example.com/v1/devices | jq '.[] | {name, status}'
POST JSON payload from stdin
jq -n '{name: "sw-01", vlan: 10}' | \
curl -s -X POST https://api.example.com/v1/devices \
-H "Content-Type: application/json" \
-d @- | jq .
POST from file — large payloads or templated requests
curl -s -X POST https://api.example.com/v1/devices \
-H "Content-Type: application/json" \
-d @payload.json | jq .
Response Inspection
Show response headers only — debug content type, rate limits
curl -sI https://api.example.com/v1/devices
Show headers AND body — full round-trip visibility
curl -s -D- https://api.example.com/v1/devices | head -20
Extract HTTP status code — for scripting conditionals
status=$(curl -s -o /dev/null -w '%{http_code}' https://api.example.com/v1/health)
if [[ "$status" -ne 200 ]]; then
echo "API unhealthy: HTTP $status" >&2
exit 1
fi
Capture response time — performance monitoring
curl -s -o /dev/null -w 'DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n' \
https://api.example.com/v1/health
Authentication Patterns
Basic auth — ISE ERS pattern
curl -sk -u "$ISE_USER:$ISE_PASS" \
-H "Accept: application/json" \
https://10.50.1.20:9060/ers/config/networkdevice
Bearer token — Vault pattern
curl -s -H "X-Vault-Token: $VAULT_TOKEN" \
https://10.50.1.60:8200/v1/secret/data/domus/api-keys | jq '.data.data'
Retry and Error Handling
Retry with exponential backoff
for attempt in 1 2 3 4 5; do
response=$(curl -s -w '\n%{http_code}' https://api.example.com/v1/data)
status=$(echo "$response" | tail -1)
body=$(echo "$response" | sed '$d')
if [[ "$status" -eq 200 ]]; then
echo "$body" | jq .
break
elif [[ "$status" -eq 429 ]]; then
retry_after=$(curl -sI https://api.example.com/v1/data | grep -i retry-after | awk '{print $2}' | tr -d '\r')
sleep "${retry_after:-$(( 2 ** attempt ))}"
else
echo "Attempt $attempt failed: HTTP $status" >&2
sleep $(( 2 ** attempt ))
fi
done
Silent failure detection — curl exit code vs HTTP status
# curl exit 0 means TCP success, NOT HTTP success
# Always check HTTP status separately
if ! curl -sf https://api.example.com/v1/health > /dev/null; then
echo "Request failed (network or HTTP error)" >&2
fi
Output Formatting
Write response body to file while showing progress
curl -o response.json https://api.example.com/v1/export
Pipe through jq for filtered output
curl -s https://api.example.com/v1/devices | \
jq -r '.[] | [.name, .ip, .status] | @tsv' | \
column -t
Save headers and body separately
curl -s -D headers.txt -o body.json https://api.example.com/v1/devices
Multipart and File Upload
Upload file with multipart form
curl -s -X POST https://api.example.com/v1/upload \
-H "Authorization: Bearer $TOKEN" \
-F "file=@backup.tar.gz" \
-F "description=ISE config backup"
Proxy and TLS
Skip certificate verification — lab/dev only
curl -sk https://self-signed.lab.local/api/v1/data
-k disables TLS verification. Never use in production scripts. Pin the CA cert instead with --cacert.
|
Use specific CA certificate
curl -s --cacert /etc/ssl/certs/domus-ca.pem \
https://vault-01.inside.domusdigitalis.dev:8200/v1/sys/health
Verbose output — debug TLS handshake and headers
curl -v https://api.example.com/v1/health 2>&1 | grep -E '^\*|^[<>]'