cURL to Python, JavaScript or Go: what actually changes
Copying a cURL command into code looks like a find-and-replace job. It isn't. Each runtime has its own defaults for body encoding, redirects and TLS, and those defaults decide whether your translated request behaves like the one you tested in the terminal.
Every request is four decisions
A cURL command compresses an HTTP request into flags: the method, the URL, the headers, and an optional body. The flags are not the request — they are instructions for curl's own defaults. -X POST sets the method, -H adds a header, -d supplies a body and, importantly, changes the implied method to POST and the content type to application/x-www-form-urlencoded unless you override it.
curl 'https://api.example.com/v1/orders' \
-H 'Authorization: Bearer sk_live_8241' \
-H 'Content-Type: application/json' \
-d '{"customer":"cus_8241","items":[{"sku":"CM-01","qty":2}]}'Python: requests wants a dict, not a JSON string
The requests library will happily send a raw string, but then you are responsible for the content type and for getting the escaping right. Passing json= instead serialises a Python dict, sets Content-Type: application/json, and avoids the double-encoding bug where a JSON string ends up quoted inside another JSON string. That bug is the single most common mistake in hand-written translations.
import requests
response = requests.post(
url,
headers=headers,
json=payload,
timeout=30,
)Two defaults matter. requests follows redirects by default, where curl needs -L — so a 301 that curl showed you will be invisible in Python. In the other direction, requests verifies TLS certificates unless you pass verify=False, so a command that worked with -k will fail here in a way that looks like an auth error.
JavaScript: fetch wants a string
fetch takes a body as a string, a FormData, a URLSearchParams, or a blob — never a bare object. That is why every generator wraps the payload in JSON.stringify. Like requests, fetch follows redirects by default, so the -L flag often needs no translation at all. The reverse is true: if the original command deliberately did not follow redirects, the browser will.
const response = await fetch(url, {
method: "POST",
headers,
body: JSON.stringify(payload),
});
if (!response.ok) {
throw new Error(`Request failed: ${response.status}`);
}One thing browsers cannot do is disable TLS verification. -k has no fetch equivalent, by design. If you genuinely need it, the request has to run in Node with a custom agent — not in a tab.
Go: a reader, a client, and a body to close
Go makes you build the request explicitly: a method, a URL, and an io.Reader for the body. It also makes you close the response body, which is the line everyone forgets when copying snippets. The default http.Client follows redirects, matching fetch rather than curl.
req, err := http.NewRequest("POST", url, strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()The flags that quietly change behaviour
-Lfollows redirects. curl does not by default; fetch, Go and Python's requests all do. That mismatch is silent until an endpoint returns a 301.-kdisables certificate verification. Never carry this into production code.-dsets a form content type unless you override it. Sending JSON without-H 'Content-Type: application/json'is a real bug, not a formatting detail.-u user:passis not a custom header — it generates a Basic Authorization header from the credentials.--compressedasks for gzip. Modern clients handle this automatically, so the generated code usually needs no equivalent.
Paste the command and get the request in all three languages, with the flags already translated.
Open the cURL converter