curl is not a download tool with flags. It is a request builder that shows
you exactly what an API saw, which makes it the fastest debugging
instrument you own. Here are three API problems we solved with it, each in
under ten minutes, each a pattern you can copy.
Session 1: proving a 204 worked
We resubmitted a sitemap through the Search Console API. The response was
HTTP 204, which means success with no body. Nothing to read, no receipt.
The question was whether the submission actually registered.
The check is a GET against the same resource immediately after:
curl -s -H "Authorization: Bearer $TOKEN" \
"https://searchconsole.googleapis.com/webmasters/v3/sites/.../sitemaps"
The response lists lastSubmitted and lastDownloaded per sitemap. Ours
showed a new submitted timestamp and a download eight seconds later. The
204 was real.
Pattern: for any write endpoint returning an empty success code, verify
with a read of the same resource before declaring victory. 200-family
codes with no body are commitments, not confirmations.
Session 2: a batch POST that silently did nothing
We sent 1,495 URLs to the IndexNow API as one JSON array. The endpoint
returned 200. Later analysis showed a batch built differently had carried
an empty URL list, and the endpoint still returned 200. IndexNow
acknowledges receipt, not processing, and definitely not list validity.
The fix was client-side validation plus response capture:
curl -sS -w "\n%{http_code}\n" -X POST \
-H "Content-Type: application/json" \
--data-binary @payload.json \
"https://api.indexnow.org/indexnow"
Three details carry the value. `-sS` silences the progress bar but keeps
error messages. `-w "%{http_code}"` prints the status even when the body
is empty. `--data-binary @file` sends the payload byte-exact, where `-d`
can mangle content on some platforms when the payload is large.
Pattern: log the request body size before sending. One line comparing the
URL count in the file against the count in the array catches the empty
batch before the endpoint happily accepts it.
Session 3: credentials versus network path
A CI job failed to authenticate against a private registry. The error said
unauthorized, which reads as a credentials problem. The credentials were
fine.
Two curls separated the possibilities:
curl -sk -o /dev/null -w "%{http_code}\n" https://registry.example/v2/
# from outside: 404
curl -sk -u "$USER:$PASS" -o /dev/null -w "%{http_code}\n" \
https://registry.example/v2/_catalog
# from a pod inside the network: 200
The registry answered 404 from outside because the public route no longer
existed, and 200 with credentials from inside. Unauthorized was a routing
message, not an auth message.
Pattern: when an API rejects you, test the same endpoint from a different
network position before touching the credentials. A 401 from one path and
a 200 from another means your credentials were never the problem.
The flag set worth memorizing
- `-sS`: quiet but honest. Errors print, progress does not.
- `-w "%{http_code} %{time_total}\n"`: status and timing on one line, the
cheapest profiling you will ever do.
- `-D -`: dump response headers to stdout. Authentication and caching
problems live in headers, not bodies.
- `-H @headers.txt`: send a saved header set, reproducible across runs.
- `--data-binary @file`: byte-exact payloads, mandatory for JSON batches.
- `-o /dev/null`: throw away the body when only the status matters.
Headers tell you which layer lied
Every distributed API problem is a question of which layer produced the
answer. Read these three header groups first:
1. Server and via headers: which proxy answered.
2. Cache status headers: whether you saw an edge copy or the origin.
3. WWW-Authenticate on a 401: the expected scheme, which the client may
not be sending.
In the registry session, the cache and server headers differed between
the two network positions, which is what turned an auth investigation
into a routing one.
Checklist for the next failing integration
1. Reproduce with curl before reading the client library's code. Library
bugs hide behind wrapper errors.
2. Capture status, headers, and timing in the same run.
3. Validate the payload client-side. Count records before sending them.
4. Retry the exact same request from another network position.
5. Save the working command in the repo. The next person should start
from a known-good request, not from the manual.
---
What is the API failure that curl untangled fastest for you? If you build
these requests often, our curl command builder assembles headers, methods,
and payloads visually and outputs a copy-paste command:
https://webrecast.com/en/curl-builder