Skip to main content
Guides

How to Convert a cURL Command to Python (requests)

By Mithun··8 min read
Quick Answer

Every part of a cURL command maps cleanly onto Python's requests library: -X sets the method (requests.post), -H becomes headers={}, a JSON -d payload becomes json={}, form data becomes data={}, -u becomes auth=(), and query params become params={}. Fastest way: paste it into an online cURL → Python converter. To do it by hand, use the flag-by-flag table below — I ran both the cURL command and the generated Python against a live echo server and they produced identical results.

You copy a working curl command from an API's docs (or from your browser's "Copy as cURL"), and now you need it as Python. The good news: the translation is almost mechanical, because every cURL flag has a direct equivalent in the requests library. Once you've seen the mapping, you can convert any command in seconds.

Below is the complete flag-by-flag map, the two most common real cases (a JSON POST and a GET with params), and — because this is meant to be trustworthy — proof that the converted Python behaves exactly like the original cURL, tested against a live server.

The flag-by-flag map (cURL → requests)

This table covers virtually every cURL command you'll meet. Learn it once and the conversion becomes automatic:

cURL flagrequests equivalentWhat it does
-X POSTrequests.post(...)HTTP method
-H "K: V"headers={"K": "V"}Request header
-d '{"a":1}' (JSON)json={"a": 1}JSON body (sets Content-Type)
-d "a=b&c=d"data={"a": "b", "c": "d"}Form-encoded body
-G -d "q=x"params={"q": "x"}Query-string params
-u user:passauth=("user", "pass")Basic auth
-b "k=v"cookies={"k": "v"}Cookies
-F "file=@f.png"files={"file": open("f.png","rb")}Multipart upload
-A "agent"headers={"User-Agent": "agent"}User agent
-Lallow_redirects=True (default)Follow redirects
-k / --insecureverify=FalseSkip TLS verification

The single most common mistake: using data= for a JSON body. Use `json=` — it serializes the dict *and* sets Content-Type: application/json for you. Use data= only for form-encoded (application/x-www-form-urlencoded) bodies.

Example 1 — a JSON POST with headers (tested)

Here's a typical authenticated API call in cURL:

curl -X POST https://postman-echo.com/post \
-H "Content-Type: application/json" \
-H "Authorization: Bearer tok_123" \
-d '{"name":"mithun","plan":"pro"}'
the cURL command

And the direct requests translation — -X POSTrequests.post, the two -H flags → headers={}, the JSON -djson={}:

import requests
r = requests.post(
"https://postman-echo.com/post",
headers={
"Content-Type": "application/json",
"Authorization": "Bearer tok_123",
},
json={"name": "mithun", "plan": "pro"},
)
print(r.status_code, r.json()["json"])
the Python equivalent

I ran both against the live echo server. They returned the same thing — the server saw an identical body and auth header either way:

# curl -> body: {'name': 'mithun', 'plan': 'pro'} | auth: Bearer tok_123
# requests -> 200 {'name': 'mithun', 'plan': 'pro'} | auth: Bearer tok_123
output — cURL and requests match, byte for byte

Example 2 — a GET with query params

Query strings are where hand-conversion trips people up. Don't paste ?q=python&page=2 into the URL — pass a params dict and let requests build the query string (and URL-encode it) for you:

# curl "https://postman-echo.com/get?q=python&page=2" -A "my-app/1.0"
import requests
r = requests.get(
"https://postman-echo.com/get",
params={"q": "python", "page": "2"},
headers={"User-Agent": "my-app/1.0"},
)
print(r.json()["args"]) # -> {'q': 'python', 'page': '2'}
cURL → requests, with params

Tested: the server echoed {'q': 'python', 'page': '2'} and the custom User-Agent came through — exactly as the cURL version. Using params also means special characters get encoded correctly, which is easy to get wrong by hand.

The fast way: an online converter

When you just want the Python and don't want to think about flags, paste the whole command into the free cURL to Python converter. It parses the command — method, headers, body, auth, params — and returns ready-to-run requests code. It runs in your browser.

Whichever method you use, mind embedded credentials: cURL commands copied from docs or DevTools often contain real API keys, cookies, or bearer tokens. Don't commit the converted code with a token inline — load it from an environment variable instead. (See how to protect API keys in Python.)

Gotchas worth knowing

  • JSON vs form: -d '{...}' is *usually* JSON → use json=. But -d "a=b&c=d" is form data → use data=. cURL doesn't distinguish; you have to.
  • `requests` follows redirects by default — cURL does not unless you pass -L. If you're matching cURL exactly, add allow_redirects=False.
  • Cookies and sessions: for multiple calls that share cookies/auth, use a requests.Session() instead of repeating headers on every call.
  • File uploads: -F "file=@photo.png" becomes files={"file": open("photo.png", "rb")} — and don't also set Content-Type by hand; requests sets the multipart boundary for you.
  • `--insecure`/`-k` maps to verify=False, but only use it for local testing — it disables TLS verification.

“curl in Python”: there is no `curl` command — here’s what to use

Not every search for curl in Python wants to convert a specific command — a lot of people just want to make the *same kind of HTTP request* from Python. Python has no built-in curl, so you have three real options, in the order you should reach for them:

  1. `requests` — the idiomatic way (recommended). Everything on this page maps a cURL command onto requests. It's pure Python, needs no curl binary, and gives you .json(), sessions, and clean error handling.
  2. `subprocess` — actually run the real `curl` binary from Python. Use this when you need cURL's exact behavior, or a flag requests doesn't expose. It shells out to the same curl you'd type in a terminal.
  3. `pycurl` — a binding to libcurl (the C library that powers cURL itself). Maximum control and performance, but heavier to install and far more verbose — only worth it for special cases.

The subprocess route runs the exact command you'd type by hand. I ran this against a live echo server:

import subprocess, json
out = subprocess.run(
["curl", "-s", "-X", "POST", "https://postman-echo.com/post",
"-H", "Content-Type: application/json",
"-d", json.dumps({"name": "mithun", "plan": "pro"})],
capture_output=True, text=True,
)
print(out.returncode, json.loads(out.stdout)["json"])
# -> 0 {'name': 'mithun', 'plan': 'pro'}
Calling the real curl binary from Python with subprocess — tested

For anything normal, prefer `requests` — it doesn't depend on a curl binary being installed, it's easier to read, and errors come back as Python exceptions instead of exit codes you have to parse. Reach for subprocess or pycurl only when you specifically need cURL/libcurl behavior.

The reverse: turn Python `requests` back into a `curl` command

Sometimes you need to go the *other* direction — you have working requests code and want the equivalent curl command to share a repro, paste into a bug report, or test in a terminal. The curlify library does it from a prepared request:

import requests, curlify
req = requests.Request(
"POST", "https://postman-echo.com/post",
headers={"Authorization": "Bearer tok_123"},
json={"name": "mithun", "plan": "pro"},
)
prepared = requests.Session().prepare_request(req)
print(curlify.to_curl(prepared))
requests → curl with curlify
curl -H 'Authorization: Bearer tok_123' \
-H 'Content-Type: application/json' \
-d '{"name": "mithun", "plan": "pro"}' \
https://postman-echo.com/post
Real output (default headers trimmed for readability)

One honest caveat from my run: curlify also emits the headers requests adds automatically — User-Agent: python-requests/…, Accept, Accept-Encoding, Connection — so the real output is noisier than above. Drop the ones you don't care about and you've got a clean, runnable cURL command.

Convert your cURL command — free

Paste a cURL command and get ready-to-run Python requests code. In your browser, no signup.

Open the cURL → Python tool

Free tools mentioned here

Frequently asked questions

How do I convert a cURL command to Python?

Map each cURL flag to its requests equivalent: -X sets the method (requests.post), -H becomes headers={}, a JSON -d body becomes json={}, form data becomes data={}, -u becomes auth=(), and query params become params={}. Or paste the command into an online cURL-to-Python converter to get ready-to-run requests code instantly.

How do I use curl in Python?

Python has no built-in curl command. The idiomatic way is the requests library (requests.get/post), which reproduces any curl command. If you specifically need the real curl binary, call it with subprocess.run(["curl", ...]); for low-level control you can use pycurl, a binding to libcurl. For everyday HTTP, prefer requests — it needs no curl binary and returns Python objects with proper error handling.

How do I convert Python requests back into a curl command?

Use the curlify library: build or capture a requests PreparedRequest, then call curlify.to_curl(prepared) to get the equivalent curl command. Note that curlify includes the headers requests adds automatically (User-Agent, Accept, Connection), so you'll usually trim those before sharing the command.

Should I use json= or data= in requests?

Use json= for a JSON body — it serializes the dict and automatically sets Content-Type: application/json. Use data= only for form-encoded bodies (a=b&c=d) or raw strings. Using data= with a Python dict sends form-encoded data, not JSON, which is the most common conversion bug.

How do I convert curl query parameters to requests?

Pass a params dict to requests rather than putting the query string in the URL: requests.get(url, params={'q': 'python', 'page': '2'}). requests builds and URL-encodes the query string for you, which avoids encoding mistakes you'd make appending ?q=...&page=... by hand.

Does requests follow redirects like curl?

By default requests follows redirects automatically, whereas curl only follows them when you pass -L. If you need to match a plain curl command exactly (no -L), set allow_redirects=False; if the curl had -L, the default requests behavior already matches.

Is it safe to use an online curl-to-python converter?

It's fine for commands without secrets. But cURL commands copied from API docs or browser DevTools often contain real tokens, cookies, or API keys — prefer a converter that runs in your browser, and never commit the generated code with the token inline; load it from an environment variable instead.

Keep reading