cURL Converter: Convert cURL to Python, JavaScript & More
Three Myths About cURL Commands and Code Generation
Myth 1: “cURL is a Linux developer tool — I use Python/JavaScript, so it doesn't affect me.”
Reality: Every API documentation page shows cURL examples. Every browser's DevTools Network tab has “Copy as cURL.” If you integrate with any third-party API, you will encounter cURL commands — converting them into your language is a daily task.
Myth 2: “Converting curl to Python is trivial — just change the flags to keyword arguments.”
Reality: -d vs --data-raw have different semantics. --compressed affects how the response body is decoded. Cookie jars, redirect following, and Basic auth each require specific handling in every target language. Naive conversion silently produces broken code.
Myth 3: “A curl converter tool handles everything automatically.”
Reality: Converters handle the mechanical mapping. You still need to understand what each flag means to validate the output — especially for authentication, TLS verification flags (-k), and multipart uploads.
curl was created by Daniel Stenberg in 1998 as a tool for transferring data with URL syntax. Today it handles 26+ protocols and ships pre-installed on macOS, Windows 10+, and every major Linux distribution. Per the Stack Overflow 2025 Developer Survey, curl appears in over 78% of developers' weekly tool usage for API testing and scripting. Its command-line syntax has become the de facto standard for describing HTTP requests — which is exactly why you need to know how to convert it.
The open-source curlconverter project (version 4.12.0, github.com/curlconverter/curlconverter) supports generating code in 29 languages and tools: Python, JavaScript (fetch + axios), Node.js, Go, Java, C#, PHP, Ruby, Rust, Swift, Dart, Kotlin, Perl, R, MATLAB, Elixir, PowerShell, Wget, HTTPie, Ansible, and more. This guide explains the flag mappings, shows the conversion patterns that actually matter in production, and documents where converters fall short.
Key Takeaways
- ▸curl was created in 1998 by Daniel Stenberg. Per Stack Overflow 2025, it is used by over 78% of developers weekly for API testing. Its syntax is the universal language for describing HTTP requests.
- ▸curlconverter (npm v4.12.0) supports 29 target languages. It correctly handles most flags — but you must manually verify
-k(TLS skip),-L(redirects), cookie jars, and multipart uploads. - ▸
-dreads from files if value starts with@and strips newlines.--data-rawsends the value exactly as given. Always use--data-rawfor JSON bodies to avoid surprises. - ▸
-u user:pass→Authorization: Basic base64(user:pass). In Python requests, useauth=("user","pass"). Never hardcode credentials — use environment variables. - ▸The
--compressedflag addsAccept-Encoding: gzipand handles decompression. Most HTTP libraries handle this automatically when you set the header — but some require explicit decompression code.
Anatomy of a cURL Command: Flag Reference
A curl command for a POST request to an API looks like this:
curl -X POST 'https://api.example.com/v1/orders' -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...' -H 'Content-Type: application/json' -H 'Accept: application/json' --data-raw '{"item_id": 42, "quantity": 3, "coupon": "SAVE10"}' --compressed -L --max-redirs 3Here is what each component means, and how it maps to your target language:
| curl Flag | What It Does | Python requests | Notes |
|---|---|---|---|
| -X METHOD | HTTP method (GET/POST/PUT/PATCH/DELETE) | requests.post() / method= | GET is default if no -X and no -d |
| -H 'Key: Val' | Request header | headers={"Key": "Val"} | Multiple -H flags = multiple headers |
| -d 'data' | Request body — reads file if starts with @ | data='data' | Also sets method to POST; strips newlines |
| --data-raw 'data' | Body sent literally — no @ file reading | data='data' | Preferred for JSON bodies |
| -u user:pass | HTTP Basic authentication | auth=('user', 'pass') | Base64-encodes credentials automatically |
| -k / --insecure | Skip TLS certificate verification | verify=False | Security risk — fix the cert instead |
| -L / --location | Follow redirects (3xx) | allow_redirects=True (default) | requests follows redirects by default |
| --compressed | Request gzip and decompress response | headers: Accept-Encoding: gzip | requests + urllib3 decompress automatically |
| -F 'key=@file' | Multipart/form-data file upload | files={'key': open(...)} | Sets Content-Type: multipart/form-data |
| -b 'name=val' | Send cookie | cookies={'name':'val'} | Use requests.Session() for cookie jar |
| --max-time N | Total transfer timeout in seconds | timeout=N | requests timeout is connect+read combined |
Conversion Examples: curl to Python, JavaScript, and Go
Example 1: JSON POST with Bearer Token → Python
curl -X POST https://api.stripe.com/v1/payment_intents -H 'Authorization: Bearer sk_test_abc123' -H 'Content-Type: application/x-www-form-urlencoded' -d 'amount=2000¤cy=usd&payment_method_types[]=card'
import os
import requests
# NEVER hardcode secrets — use environment variables
api_key = os.environ["STRIPE_SECRET_KEY"]
response = requests.post(
"https://api.stripe.com/v1/payment_intents",
headers={"Authorization": f"Bearer {api_key}"},
# Content-Type: application/x-www-form-urlencoded is set automatically by data=
data={
"amount": "2000",
"currency": "usd",
"payment_method_types[]": "card",
},
timeout=30,
)
response.raise_for_status() # Raises HTTPError for 4xx/5xx
result = response.json()
print(result["id"]) # pi_abc123...Example 2: JSON Body POST → JavaScript (fetch)
curl -X POST https://api.example.com/v1/users -H 'Authorization: Bearer TOKEN' -H 'Content-Type: application/json' --data-raw '{"name":"Alice","email":"[email protected]","role":"admin"}'const token = process.env.API_TOKEN // Never hardcode
async function createUser(name: string, email: string, role: string) {
const response = await fetch('https://api.example.com/v1/users', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ name, email, role }),
})
if (!response.ok) {
// Consume the body to avoid memory leaks, even on error
const errorBody = await response.text()
throw new Error(`API error ${response.status}: ${errorBody}`)
}
return response.json() as Promise<{ id: string; name: string }>
}
// Usage
const user = await createUser('Alice', '[email protected]', 'admin')
console.log(user.id)Example 3: GET with Query Parameters → Go
curl 'https://api.github.com/search/repositories?q=jsonpath&sort=stars&per_page=5' -H 'Accept: application/vnd.github+json' -H 'Authorization: Bearer ghp_abc123' -H 'X-GitHub-Api-Version: 2022-11-28'
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"time"
)
type SearchResult struct {
TotalCount int `json:"total_count"`
Items []struct {
FullName string `json:"full_name"`
Stars int `json:"stargazers_count"`
} `json:"items"`
}
func searchRepos(query string) (*SearchResult, error) {
params := url.Values{}
params.Set("q", query)
params.Set("sort", "stars")
params.Set("per_page", "5")
reqURL := "https://api.github.com/search/repositories?" + params.Encode()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
req, _ := http.NewRequestWithContext(ctx, "GET", reqURL, nil)
req.Header.Set("Accept", "application/vnd.github+json")
req.Header.Set("Authorization", "Bearer "+os.Getenv("GITHUB_TOKEN"))
req.Header.Set("X-GitHub-Api-Version", "2022-11-28")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API error: %d", resp.StatusCode)
}
var result SearchResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}Authentication Pattern Conversions
Authentication is where most curl-to-code conversions go wrong. Each auth type has a specific curl idiom that maps to language-specific patterns:
# ── 1. HTTP Basic Auth ──────────────────────────────────────────────────────
# curl
curl -u myuser:mypassword https://api.example.com/resource
# Python requests (recommended — HTTPBasicAuth handles base64 encoding)
requests.get(url, auth=("myuser", os.environ["API_PASSWORD"]))
# JavaScript fetch (manual — no native Basic auth helper)
const credentials = btoa('myuser:' + password)
fetch(url, { headers: { 'Authorization': 'Basic ' + credentials } })
# ── 2. Bearer Token (OAuth 2.0 / API Key as Bearer) ─────────────────────────
# curl
curl -H 'Authorization: Bearer eyJhbGci...' https://api.example.com
# Python requests
requests.get(url, headers={"Authorization": f"Bearer {os.environ['TOKEN']}"})
# JavaScript fetch
fetch(url, { headers: { 'Authorization': `Bearer ${process.env.TOKEN}` } })
# ── 3. API Key in Header ─────────────────────────────────────────────────────
# curl
curl -H 'X-API-Key: abc123def456' https://api.example.com
# Python requests
requests.get(url, headers={"X-API-Key": os.environ["API_KEY"]})
# ── 4. API Key in Query Parameter ────────────────────────────────────────────
# curl
curl 'https://api.example.com/data?api_key=abc123'
# Python requests (use params= not raw string — handles encoding)
requests.get(url, params={"api_key": os.environ["API_KEY"]})
# JavaScript fetch (use URLSearchParams)
const params = new URLSearchParams({ api_key: process.env.API_KEY })
fetch(`https://api.example.com/data?${params}`)Security rule: When you see a Bearer token or API key in a curl command from API docs, it is always a placeholder or test credential. Never paste real credentials into a curl converter website — the value is logged server-side in most tools. Use curlconverter locally via npx curlconverter or replace the credential with a placeholder before pasting.
File Uploads and Multipart Form Data
The -F flag in curl creates multipart/form-data requests — used for file uploads and mixed form/file submissions. This is the conversion that most tools get partially wrong, because multipart requires both the file content and the correct MIME type boundary.
# curl -F sends multipart/form-data
curl -X POST https://api.example.com/upload -H 'Authorization: Bearer TOKEN' -F 'file=@/path/to/report.pdf;type=application/pdf' -F 'title=Q1 Report' -F 'category=financial'
# ── Python requests ──────────────────────────────────────────────────────────
import requests
with open('/path/to/report.pdf', 'rb') as f:
response = requests.post(
'https://api.example.com/upload',
headers={'Authorization': 'Bearer ' + token},
# Do NOT set Content-Type manually — requests generates the boundary
files={
'file': ('report.pdf', f, 'application/pdf'),
},
data={
'title': 'Q1 Report',
'category': 'financial',
},
)
# ── JavaScript (fetch + FormData) ────────────────────────────────────────────
const form = new FormData()
form.append('file', fileBlob, 'report.pdf') // fileBlob = File or Blob object
form.append('title', 'Q1 Report')
form.append('category', 'financial')
// Do NOT set Content-Type: multipart/form-data manually —
// the browser/Node sets it with the correct boundary
const response = await fetch('https://api.example.com/upload', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: form,
})
# ── Node.js: reading a file for upload ──────────────────────────────────────
import { readFileSync } from 'fs'
import FormData from 'form-data' // npm install form-data
const form = new FormData()
form.append('file', readFileSync('./report.pdf'), {
filename: 'report.pdf',
contentType: 'application/pdf',
})
form.append('title', 'Q1 Report')
await fetch('https://api.example.com/upload', {
method: 'POST',
headers: { ...form.getHeaders(), Authorization: `Bearer ${token}` },
body: form,
})Common Conversion Pitfalls and How to Fix Them
-d vs --data-raw: The Silent Data Corruption Bug
# -d and --data-raw behave differently:
# -d '@filename' → reads the CONTENTS of the file as the body
# -d '@variable' → if the string literally starts with @, reads from that path
# -d 'data' → also strips embedded newlines from the value
# --data-raw '@value' → sends the literal string "@value" — no file reading
# --data-raw 'data' → sends exactly as given, newlines preserved
# Problem: -d with a JSON body that has @ in it (email addresses)
curl -d '{"email":"[email protected]","name":"Alice"}' https://api.example.com/users
# curl will NOT try to read from "example.com" — @ must be the FIRST character
# for file reading. But --data-raw is unambiguous and always safer for JSON.
# Safe pattern:
curl --data-raw '{"email":"[email protected]"}' -H 'Content-Type: application/json' https://api.example.com/users--compressed: Most Libraries Handle It, Some Don't
# curl --compressed adds: Accept-Encoding: gzip, deflate, br
# AND automatically decompresses the response body
# Python requests: urllib3 decompresses gzip automatically when header is set
# No extra code needed — just set the header if the server requires it:
requests.get(url, headers={"Accept-Encoding": "gzip, deflate, br"})
# JavaScript fetch: the browser/Node.js automatically decompresses
# Content-Encoding: gzip responses. Setting Accept-Encoding is fine.
# Go: net/http does NOT automatically decompress unless you set:
transport := &http.Transport{ DisableCompression: false } // default
// Or explicitly: go get golang.org/x/net/http2
// In practice, Go's http.Client decompresses gzip transparently
// UNLESS you set DisableCompression: true
# Gotcha: AWS Lambda, Vercel edge functions
# Some runtimes strip Accept-Encoding and handle compression at infra level
# If you get double-decompressed garbage, remove the Accept-Encoding header-k / --insecure: Never Convert This to Production Code
The -k flag tells curl to skip TLS certificate verification. In Python this becomes verify=False. In JavaScript it requires a custom Agent with rejectUnauthorized: false. Both approaches completely defeat TLS — they leave your connection vulnerable to man-in-the-middle attacks and make security scanners (Snyk, SonarQube) flag your code.
The correct fix depends on why verification fails: for self-signed development certificates, add the cert to your trust store or set REQUESTS_CA_BUNDLE environment variable. For expired production certificates, renew them — Let's Encrypt automates this for free. For corporate proxy certificates, add the proxy CA to the system trust store. See the HTTPS and TLS guide for certificate chain debugging.
Using curlconverter: CLI, npm, and VS Code
# Method 1: npx (no installation required)
npx curlconverter --language python "curl -X POST https://api.example.com/data -H 'Authorization: Bearer TOKEN' -d '{"key":"value"}'"
# Method 2: Global install
npm install -g curlconverter
echo "curl https://api.example.com" | curlconverter --language go
# Method 3: Supported --language values (29 options):
# python, javascript, node, go, java, csharp, php, ruby, rust, swift,
# dart, kotlin, perl, r, matlab, elixir, powershell, wget, httpie,
# ansible, har, json, cfml, clojure, lua, objc, ocaml, julia, brainfuck
# Method 4: In code (convert programmatically)
import { toPython } from 'curlconverter'
const pythonCode = toPython(`curl -X POST https://api.example.com \
-H 'Content-Type: application/json' \
--data-raw '{"key":"value"}'`)
console.log(pythonCode)For browser-based one-off conversions, curlconverter.com lets you paste a curl command and pick your target language from a dropdown. The tool is open source and the web interface does not store your commands server-side — but as a rule, always replace real credentials with placeholders before using any online tool. Use npx curlconverter locally for commands containing real tokens.
Frequently Asked Questions
How do I convert a cURL command to Python?
Use curlconverter.com or npx curlconverter --language python "curl ...". The converter maps -X to the requests method, -H to the headers dict, -d/--data-raw to the data or json parameter, and -u user:pass to auth=("user","pass"). If your body is JSON (Content-Type: application/json), the converter should use json= instead of data= — check the output for this. Always replace hardcoded credentials with os.environ["KEY"] in production code.
What is the difference between -d and --data-raw?
-d (--data) reads from a file if the value starts with @, strips embedded newlines, and URL-encodes the @ character. --data-raw sends the value exactly as given — no @ file reading, no encoding. For JSON bodies, always use --data-raw to avoid ambiguity. Multiple -d flags are concatenated with & (like HTML form data); --data-raw flags are concatenated without encoding.
How do I convert curl Basic auth (-u) to Python?
curl -u username:password sends Authorization: Basic base64(username:password). In Python requests: requests.get(url, auth=("username", password)) using HTTPBasicAuth automatically. For manually building the header: import base64; header = "Basic " + base64.b64encode(b"user:pass").decode(). Never hardcode credentials — use os.environ["PASSWORD"] or a secrets manager.
Why does my converted code fail when the curl command works?
Common causes: 1) Missing Content-Type header (curl infers it from -d, your HTTP library may not set it automatically). 2) --compressed not handled — add Accept-Encoding: gzip. 3) -k/--insecure skipping TLS (set verify=False only to debug, not in production). 4) Cookie state not replicated (curl -c/-b manages a cookie jar, your library may need explicit cookie handling). 5) Redirect behavior difference (-L follows by default in curl, behavior varies by library).
How many languages does curlconverter support?
curlconverter v4.12.0 (github.com/curlconverter/curlconverter) supports 29 targets: Python, JavaScript (fetch), Node.js (axios), Go, Java, C#, PHP, Ruby, Rust, Swift, Dart, Kotlin, Perl, R, MATLAB, Elixir, PowerShell, Wget, HTTPie, Ansible URI module, HAR, JSON, ColdFusion, Clojure, Lua, Objective-C, OCaml, Julia, and Brainfuck.
How do I convert a multipart file upload curl command?
curl -F "file=@path/to/file.pdf" sends multipart/form-data. In Python requests: use the files= parameter with a tuple (filename, fileobj, mimetype) — do NOT set Content-Type manually. In JavaScript fetch: use FormData and append() — do NOT set Content-Type manually. Both automatically generate the multipart boundary. Setting Content-Type: multipart/form-data manually will break boundary generation.
Is it safe to paste curl commands with tokens into online converters?
No — assume any text you paste into an online tool is logged. API tokens and Bearer tokens in curl commands should be replaced with a placeholder like TOKEN before pasting. Use curlconverter locally with npx curlconverter for commands containing real credentials. The curlconverter npm package and curlconverter.com source code are both open source, but server-side logging is outside your control.
Parse and Format API Responses
After converting your curl command to code and running it, use BytePane's JSON formatter to inspect and validate the API response structure before processing it in your application.
Open JSON Formatter →