cURL is the lingua franca of APIs. Open the docs of Stripe, GitHub, OpenAI, Twilio or any serious REST API: the request examples are almost always curl commands. It is the most concise, language-neutral way to describe an HTTP call: method, URL, headers, body. The friction appears when you have to go from that command-line example to the code that actually runs inside your application: a fetch in the frontend, a requests client in a Python script, a cURL call in a PHP backend. This tool does exactly that translation, keeping the HTTP semantics intact.
What the parser reads. The command is tokenized honouring shell quoting rules (single quotes, double quotes, backslash escapes), then each option is mapped to the corresponding HTTP concept:
-X, --request sets the method (GET, POST, PUT, PATCH, DELETE). If it is missing but a body is present, the method becomes POST, exactly as cURL does.-H, --header adds a request header. It is repeatable: -H "Authorization: Bearer ..." -H "Content-Type: application/json".-d, --data / --data-raw / --data-binary defines the body. Multiple -d are joined with &. With no explicit Content-Type, cURL uses application/x-www-form-urlencoded.--json (cURL 7.82+) is a shortcut for body plus Content-Type: application/json plus Accept: application/json.-u, --user user:password produces the Authorization: Basic header with the pair base64-encoded.-b, --cookie sets the Cookie header.-F, --form builds a multipart/form-data body: -F "field=value" for a field, -F "file=@path" for an upload.- The query string is part of the URL and is preserved as-is.
fetch, requests, PHP cURL, Node: four different philosophies. The same command produces very different code depending on the target, and the differences matter.
fetch (JavaScript) is async and Promise-based, available natively in the browser and in Node from version 18. It does not serialize JSON for you: the body must be passed as a string via JSON.stringify(...), and you set the Content-Type by hand in the headers. In the browser it is subject to the target server's CORS policy.
requests (Python) is synchronous and high-level. The json= parameter serializes the dictionary and sets Content-Type: application/json automatically; data= with a dictionary produces a form-urlencoded body; files= handles multipart; auth=(user, password) does basic auth. It is the most compact target.
PHP's cURL (the libcurl extension) is imperative and verbose: curl_init(), a sequence of curl_setopt() calls (CURLOPT_CUSTOMREQUEST, CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS, CURLOPT_USERPWD), then curl_exec(). In exchange for the verbosity it gives full control over TLS, timeouts and redirects.
The Node target uses the global fetch (Node 18+), the modern idiomatic approach for a server-side HTTP client, avoiding the low-level stream-and-callback https module.
Headers, authentication and body: where sloppy converters get it wrong. A bearer token is just an Authorization: Bearer <token> header, so it passes straight through as a header in every language. Basic auth instead has to be translated: cURL uses -u user:pass, but in code it becomes btoa() in JavaScript, base64_encode() in PHP, the auth= tuple in requests. A JSON body must be serialized with the language's proper function, not pasted as a raw string. Multipart is not a simple header: it needs FormData in JS, the files= argument in requests, an associative array with CURLFile in PHP.
Privacy: everything in the browser. The command you paste often contains tokens, API keys or passwords (the -H "Authorization: ...", the -u user:pass). That is why the tool works entirely client-side: parsing and code generation happen in JavaScript in your browser, nothing is sent to a server. You can convert commands with real secrets without them leaving the machine, though the golden rule remains to replace them with environment variables in the final code.