Inspecting the exact HTTP headers that cURL sends is one of the fastest ways to explain API authentication failures, cache misses, tenant-routing mistakes, and unexpected server responses. A request can look correct at the URL level while still failing because the wrong method, Host value, token, cookie, or content-negotiation header went out on the wire.
In cURL, the practical tool for this job is --verbose, which prints protocol diagnostics to stderr while leaving the response body on stdout. The curl documentation defines > lines as headers sent by cURL and < lines as headers received from the server, so outbound request headers can be isolated with ordinary shell filters or saved to a log for later review.
Local curl config, authentication options, and cookie settings can all change which headers are emitted, so a clean baseline matters before comparing output with server logs or upstream expectations. Verbose logs can also expose bearer tokens, cookies, tenant identifiers, and internal routing values, so capture them only against safe endpoints and redact sensitive values before sharing them.
Steps to view HTTP request headers in cURL:
- Run a verbose request and discard the response body so the outgoing header block stays easy to read.
$ curl --disable --verbose --output /dev/null 'https://api.example.net/v1/tenants/acme-co/orders?status=pending' * Host api.example.net:443 was resolved. ##### snipped ##### > GET /v1/tenants/acme-co/orders?status=pending HTTP/2 > Host: api.example.net > User-Agent: curl/8.7.1 > Accept: */* > < HTTP/2 200 ##### snipped #####
Use --disable as the first option when a local curl config file might be adding flags such as a custom User-Agent or extra headers.
- Filter only the outbound request headers by merging stderr into the pipeline before matching > lines.
$ curl --disable --verbose --output /dev/null 'https://api.example.net/v1/tenants/acme-co/orders?status=pending' 2>&1 | grep '^>' > GET /v1/tenants/acme-co/orders?status=pending HTTP/2 > Host: api.example.net > User-Agent: curl/8.7.1 > Accept: */*
In curl verbose output, > marks headers sent by the client and < marks headers received from the server, while * lines describe transport activity.
- Add a routing header and confirm that cURL really sends it before debugging the application path.
$ curl --disable --verbose --header 'X-Tenant-Id: tenant_01JQ5T2H8K9N********4C6D8E1F2A' --output /dev/null 'https://api.example.net/v1/tenants/acme-co/orders?status=pending' 2>&1 | grep '^>' > GET /v1/tenants/acme-co/orders?status=pending HTTP/2 > Host: api.example.net > User-Agent: curl/8.7.1 > Accept: */* > X-Tenant-Id: tenant_01JQ5T2H8K9N********4C6D8E1F2A
Custom header checks are useful before tracing API gateways, reverse proxies, or request-signing logic.
- Repeat the check with --head when the endpoint should receive a HEAD request instead of a normal GET.
$ curl --disable --verbose --head --output /dev/null 'https://api.example.net/v1/tenants/acme-co/orders?status=pending' 2>&1 | grep '^>' > HEAD /v1/tenants/acme-co/orders?status=pending HTTP/2 > Host: api.example.net > User-Agent: curl/8.7.1 > Accept: */*
--head changes the request method, so the visible headers describe a HEAD request rather than the GET flow that many APIs and sites handle by default.
Related: How to send HEAD requests with cURL
- Save the verbose stream to a file when the request headers need to be reviewed after the command finishes.
$ curl --disable --verbose --output /dev/null 'https://api.example.net/v1/tenants/acme-co/orders?status=pending' 2> request.log
The response body stays discarded in /dev/null while the verbose stream, including sent headers, is preserved in request.log.
- Extract just the sent header lines from the saved log before comparing them with server-side traces or ticket notes.
$ grep '^>' request.log > GET /v1/tenants/acme-co/orders?status=pending HTTP/2 > Host: api.example.net > User-Agent: curl/8.7.1 > Accept: */*
Success is visible when the saved request block contains the exact method, target path, authority, and any custom header lines that the target service was expected to receive.
- Redact sensitive fields before forwarding the log to another team or attaching it to an incident.
$ sed -E \ -e 's/^(> Authorization:).*/\1 ***REDACTED***/' \ -e 's/^(> Cookie:).*/\1 ***REDACTED***/' \ -e 's/^(> X-Tenant-Id:).*/\1 ***REDACTED***/' \ request.log > request-redacted.log
Verbose request logs can expose live credentials, session state, and routing identifiers, so only share the redacted copy outside the local troubleshooting environment.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
