Curlese, five years later: curl is still the universal language of broken integrations · HyperTesto↓Skip to main content<br>Table of Contents
Almost five years ago I wrote a post (in Italian) about what I jokingly called curlese: the practice of using curl as a universal language when an HTTP integration breaks and you need to figure out whose fault it is.1 The idea was simple: instead of arguing with a provider over log files they don’t want to read, you send them a curl command. It’s self-describing, it’s reproducible, and — crucially — it’s not your code, so nobody can dismiss it as “your application is buggy”.<br>Five years later, I can confirm the thesis held up embarrassingly well. I still do this constantly. But the world around the thesis changed quite a bit, so it’s time for an update: what changed, what didn’t, and what my survival kit looks like in 2026.<br>What didn’t change #<br>The social problem is exactly where I left it. Every integration still involves at least two teams, one firewall nobody fully understands, and a conversation that starts with “works on my side”. Your perfectly clear application logs are still worthless in that conversation, because:<br>the other side can’t (or won’t) interpret your logs<br>it’s always easier to assume the problem is you<br>you’re rarely talking to the person who can actually fix it<br>A curl command with its output solves all three. It’s executable evidence. You can paste it in a ticket, the other team’s network admin can run it as-is, and the verdict is written in plain text. This part of the post needs no update at all, which is either reassuring or depressing depending on your mood.<br>What changed #<br>Quite a lot, actually.<br>HTTP/2 is everywhere, HTTP/3 is no longer exotic. In 2021 a plain HTTP/1.1 exchange was the norm for the kind of integrations I deal with. Now I regularly hit endpoints that negotiate HTTP/2, and occasionally ones where ALPN itself is part of the problem. When a request works from your laptop but hangs from a server, “they speak different HTTP versions” is now a legitimate suspect.<br>mTLS went from exotic to Tuesday. Client certificates used to be a once-a-year annoyance. Now every second B2B integration wants mutual TLS, which means a whole new category of failures (and of curl flags) that my 2021 self didn’t cover.<br>Everything is behind a WAF, a proxy, or an API gateway. Which means the error you get is often not from the application but from a bouncer in front of it, with its own ideas about which User-Agent strings deserve to exist. I once spent an afternoon proving that an endpoint worked: the provider’s edge just didn’t like a specific client. The fix was literally changing a header. The proof, as usual, was a pair of curl commands differing by one flag.<br>The lingua franca gained a new speaker. In 2026, the entity you’re explaining the problem to is increasingly not a human. A curl command with -v output is the perfect thing to paste into an LLM when you’re stuck: it’s complete, unambiguous context with zero setup. Turns out the same properties that make curl ideal for tickets make it ideal for prompts. The machines, too, speak curlese.<br>The 2026 survival kit #<br>Everything from the old post still applies (-v, -k, --connect-timeout, --trace-ascii, --trace-time — the last one saved me just a few months ago while chasing phantom delays). Here’s what earned a permanent spot since then:<br>FlagWhy it’s in the kit-w '%{time_total} %{time_connect} %{time_appconnect}'Timing breakdown. The difference between “your server is slow” and “your TLS handshake is slow” is the difference between a ticket that goes nowhere and one that gets fixed.--resolve host:port:ipTest a specific IP with the correct SNI/Host, bypassing DNS. Essential when DNS is load-balanced and only some backends are broken.--connect-to ::alt-host:Same family: redirect the connection elsewhere while keeping headers intact. Great for testing a staging backend with production URLs.--cert client.pem --key client.keymTLS. Half the time the failure is the certificate chain, and curl tells you exactly which certificate it sent and what the server said about it.--jsonSets Content-Type: application/json and POSTs the data. Small thing, but it removes a whole class of “you forgot a header” mistakes when writing repro commands.--fail-with-bodyExit code reflects the HTTP status, but you still see the error response body. Perfect for scripts and for humans.--retry 5 --retry-all-errors“It fails sometimes” is no longer an acceptable bug report. Let statistics do the talking.--no-alpnFor those special afternoons when you suspect the HTTP version negotiation itself is the problem. Rare, but when you need it, nothing else will do.A note on -w: the format string is fully customizable and criminally underused....