Curl to Code Converter
Paste a curl command and read back idiomatic client code in 12 languages — parsed on this device, with every unsupported flag named.
Generates 12 languages from one parsed request. Any flag the parser does not understand is named in the notes below rather than dropped. What curl supports here
- Method
- POST
- URL
- https://api.example.com/v1/items
- Query
- —
- Headers
- 1
- Body
- Text
- Auth
- —
- No `-X` was given, so the request body makes this a POST.
Press ? for shortcuts
Do it offline:$ curl -X POST https://api.example.com/v1/items -H 'Content-Type: application/json' -d '{"name":"widget","qty":3}'
How to use it
- Paste the command into the left pane. A badge says whether it reads as curl, and you can override it when it is wrong.
- Pick a target language. The same pasted text is re-emitted; your input is never touched.
- Check the parsed-request summary above the code — method, address, query, headers, body kind, credentials — against what you meant.
- Copy the snippet or download it with the target's extension. Any flag with no equivalent in that language is listed beside it.
Paste a curl command — the one a browser network panel or a vendor's docs handed you — and read it back as client code in twelve languages. The line is split the way a POSIX shell splits it, parsed flag by flag into a typed request, then re-emitted for the target you pick. Flags outside the covered list are named rather than dropped in silence.
How it works
Three passes run in order. A hand-written tokenizer reproduces POSIX shell word splitting: single quotes stay literal, double quotes honour the four escapes a shell honours, $'…' resolves ANSI-C sequences, and a backslash before a newline joins the lines. A flag reader walks those words into one typed request object, which is all any emitter reads.
Coverage is written down rather than implied. The target and flag lists on this page come from the emitter's frozen target array and the reader's flag table, so the page cannot promise more than the code does.
Examples
curl 'https://api.example.com/v1/search?q=ithomia&limit=10' -H 'Accept: application/json'import requests
headers = {
"Accept": "application/json",
}
response = requests.get(
"https://api.example.com/v1/search?q=ithomia&limit=10",
headers=headers,
allow_redirects=False,
)
print(response.status_code)
print(response.text)allow_redirects=False is deliberate: curl follows a redirect only when -L asks; requests follows by default.
curl -X POST https://api.example.com/v1/items -H 'Content-Type: application/json' -d '{"name":"widget","qty":3}'const response = await fetch("https://api.example.com/v1/items", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"name": "widget",
"qty": 3,
}),
redirect: "manual",
});
console.log(response.status);
console.log(await response.text());A JSON content type makes the body a literal object inside JSON.stringify, so an editor can check it.
curl -u demo:s3cr3t https://api.example.com/v1/accountpackage main
import (
"fmt"
"io"
"log"
"net/http"
)
func main() {
client := &http.Client{
CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse },
}
req, err := http.NewRequest("GET", "https://api.example.com/v1/account", nil)
if err != nil {
log.Fatal(err)
}
req.SetBasicAuth("demo", "s3cr3t")
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
out, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Status)
fmt.Println(string(out))
}demo:s3cr3t is a throwaway pair. Where a language ships a credential helper it is used, so the halves stay separate values.
curl -F 'file=@report.pdf' -F 'title=Q3 summary' https://api.example.com/v1/uploadconst axios = require("axios");
const FormData = require("form-data");
const fs = require("fs");
const form = new FormData();
form.append("file", fs.createReadStream("report.pdf"));
form.append("title", "Q3 summary");
axios({
method: "post",
url: "https://api.example.com/v1/upload",
data: form,
headers: form.getHeaders(),
maxRedirects: 0,
})
.then((response) => console.log(response.data))
.catch((error) => console.error(error));Two warnings ride along: the @ path is kept as text, never opened, and no -X appeared, so the parts decided the method.
curl -G -d 'page=2' --data-urlencode 'tag=a b' 'https://api.example.com/v1/list?sort=desc'<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.example.com/v1/list?sort=desc&page=2&tag=a+b');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$response = curl_exec($ch);
curl_close($ch);
echo $response;Both payloads land after the existing sort=desc, in written order, and no body is sent. The space becomes a plus sign, which is what curl puts on the wire.
Every example on this page is executed against the same engine that powers the tool, on every build.
Gotchas worth knowing
A trailing colon deletes a header; a semicolon sends it empty
-H 'User-Agent:' tells curl to drop a default it adds itself, so a note appears instead of an entry. -H 'X-Empty;' is the opposite, and does become a field with an empty value.
The same header name twice keeps the last value, and says so
curl puts both copies on the wire. A headers map has one slot per name, so the code carries the second value and a warning prints both.
-G turns payloads into query fields
Every -d and --data-urlencode payload is appended to the address behind any query the URL carried, and the request stays a GET with no body. Without -G they would have made it a POST.
The method is worked out the way curl's manual describes
An explicit -X wins. Failing that, -I means HEAD, any body means POST, and everything else is a GET. Where nothing was explicit the summary marks the method inferred.
-k, -x and -m do not survive equally well
Skipping certificate checks is one switch in some languages and a custom TLS client in others, and --max-time caps a whole transfer where most libraries cap connect or read time. Each says so.
Windows Copy as cURL is refused, never guessed at
The cmd.exe form escapes quotes as ^" and continues lines with a caret — a different grammar from the one parsed here. It is refused with the construct named: half a parse yields plausible code for the wrong call.
What this page will not do
It never sends the request, never opens a file named after @, and keeps no history. -d @payload.json becomes a labelled placeholder. Rebuilding a command from parts and HAR input are out of scope; twelve targets are covered and pinned.
Common errors
The ' quote opened at position 6 is never closed.- Almost always a copy that stopped early. The position points at the opening quote.
This command has no URL. Add the address curl should call.- Flags parsed cleanly but nothing was left to call — often a line ending at a backslash with no continuation.
This looks like a Windows "Copy as cURL (cmd)" or PowerShell command — ^" escaping is not part of the shell syntax this tool parses. Copy it again as "Copy as cURL (bash)".- Chrome and Edge on Windows default to the cmd flavour; the bash entry is alongside it.
`--http3` is not part of the coverage list for this tool, so it is left out of the generated code.- A warning, not a refusal: the rest still converts and the flag is named.
FAQ
How do I convert a curl command to Python?
Paste the command and leave the target on Python, the one selected when the page opens. You get a requests script: headers as a dict, a body argument matching whatever -d or -F carried, and an auth tuple when -u was present.
Which curl flags are supported?
The address itself and --url, -X, -H, the -d family including --data-raw, --data-binary and --data-urlencode, -G, -F, -u, -b, --compressed, -k, -x, -m, -A, -e, -L and -I. Output and verbosity switches get a note; everything else is named.
Is my curl command uploaded anywhere?
No. Parsing and code generation happen in the page you are looking at, and the route loads nothing from a third party. Pasted commands routinely carry a bearer token, so credential-shaped text is kept out of this device's saved-input slot, and the page says so.
Keyboard shortcuts
- ⌘/Ctrl + Enter
- Convert again after an edit.
- ⌘/Ctrl + S
- Download the code with the target's extension.
- ⌘/Ctrl + C
- Copy the code when nothing is selected.
- ⌘/Ctrl + Shift + C
- Copy the code while text is selected.
- t
- Cycle the theme: system, light, dark.
- ? or ⌘/Ctrl + /
- Open the shortcut help.
- Esc
- Close the shortcut dialog.