Debugging an API with curl: Three Real Sessions

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