Pega un comando curl y la herramienta escribe el código que hace la misma petición en JavaScript (fetch), Python (requests), Go, PHP y Node.js. Sirve el que copias de la documentación de una API y el de «Copiar como cURL» de las herramientas de desarrollo del navegador, en bash, en cmd de Windows o en PowerShell. Se convierte en tu navegador: tus cabeceras y tokens no se envían a ningún lado.
Cuidado con lo que copias del navegador. «Copiar como cURL» incluye tus cookies de sesión y, a menudo, un token en la cabecera Authorization: con ellos, cualquiera puede entrar en tu cuenta mientras sigan vigentes. La herramienta te avisa cuando los encuentra. Quítalos antes de pegar el código en un foro, un chat con una IA o un repositorio.
Qué opciones de curl entiende
- Método y dirección:
-X,-I(solo cabeceras, HEAD),-G(los datos van a la URL),--urly la URL suelta, con o sinhttp://. - Cabeceras:
-H,-A(User-Agent),-e(Referer),-bcon cookies escritas y--oauth2-bearer. Como curl,-H 'Nombre:'quita una cabecera y-H 'Nombre;'la envía vacía. - Cuerpo:
-d,--data-raw,--data-binary,--data-urlencodey--json. Con-d, curl pone por su cuentaContent-Type: application/x-www-form-urlencoded, y el código lo pone también para que el servidor reciba lo mismo. Si el cuerpo es JSON, se escribe como objeto del lenguaje. - Formularios con archivos:
-F campo=valor,-F archivo=@foto.pngcon;type=y;filename=, y--form-string. - Usuario y contraseña:
-u usuario:contraseña, con la autenticación básica de cada biblioteca. - Comportamiento:
-L(seguir redirecciones),-k(aceptar certificados no válidos),-m(tiempo máximo) y--compressed.
Lo que no cambia la petición, como -s, -v u -o, se ignora, y lo que no se puede convertir se avisa. Las comillas se interpretan como lo haría la shell: comillas simples y dobles, $'…' con \n o \xHH, el ^ de cmd y el acento grave de PowerShell.
Diferencias entre curl y cada lenguaje
- Redirecciones: curl no las sigue salvo con
-L; fetch, requests y Go sí. Por eso el código de Python, Go y Node las desactiva cuando el comando no lleva-L. En el navegador, fetch siempre las sigue. Y al seguir una, Go añade por su cuenta la cabeceraReferer. - Cabeceras prohibidas en el navegador: fetch no deja poner
Cookie,Host,Origin,Referer,Accept-Encoding,Content-Lengthni lasSec-*, que pone el propio navegador. El código de JavaScript las deja fuera y lo explica en un comentario. Además, la página tiene que ser del mismo sitio que la API, o la API debe permitirlo con CORS. El código de Node.js no tiene estas limitaciones, salvo la deHost. - Cabeceras repetidas: requests no las admite y las une separadas por comas, que para HTTP significa lo mismo.
- Campos de texto con tipo (
-F 'nota=hola;type=text/plain'): FormData y PHP solo pueden ponerle tipo a un archivo, así que el campo viaja como archivo. Y PHP no admite dos campos con el mismo nombre en el mismo formulario. - Cabeceras por defecto: cada biblioteca manda su propio
User-Agenty suAccept-Encoding. Si una API se comporta distinto con curl, suele ser por eso.
Leer un comando curl desde Python
Si necesitas procesar comandos curl en un programa, shlex, de la biblioteca estándar, los parte en palabras con las reglas de la shell:
import shlex
from urllib.parse import urlsplit
comando = """curl 'https://api.ejemplo.com/v1/pedidos?estado=pendiente' \\
-H 'Authorization: Bearer TU_TOKEN' \\
-H 'Content-Type: application/json' \\
--data-raw '{"cliente":"Ana","urgente":true}'"""
# shlex parte el texto como lo haría la shell y respeta las comillas, pero no entiende la barra del final
# de línea: hay que quitar antes cada «\» seguida de un salto
palabras = shlex.split(comando.replace("\\\n", " "))
print(palabras[:4], "…")
metodo, url, cabeceras, datos = None, None, {}, []
i = 1
while i < len(palabras):
p = palabras[i]
if p in ("-X", "--request"):
metodo = palabras[i + 1]; i += 1
elif p in ("-H", "--header"):
nombre, _, valor = palabras[i + 1].partition(":")
cabeceras[nombre.strip()] = valor.strip(); i += 1
elif p in ("-d", "--data", "--data-raw", "--data-binary"):
datos.append(palabras[i + 1]); i += 1
elif not p.startswith("-"):
url = p
i += 1
metodo = metodo or ("POST" if datos else "GET") # como curl: con -d, POST
print(metodo, urlsplit(url).netloc, urlsplit(url).path, urlsplit(url).query)
for nombre, valor in cabeceras.items():
print(f" {nombre}: {valor}")
print(" cuerpo:", "&".join(datos))$ python3 curl_a_python.py['curl', 'https://api.ejemplo.com/v1/pedidos?estado=pendiente', '-H', 'Authorization: Bearer TU_TOKEN'] …
POST api.ejemplo.com /v1/pedidos estado=pendiente
Authorization: Bearer TU_TOKEN
Content-Type: application/json
cuerpo: {"cliente":"Ana","urgente":true}Otras herramientas para desarrolladores: formateador de JSON, decodificador de JWT, codificar Base64 y URL y leer un certificado. Todas, en decodigo.com/herramientas.
Opciones de curl: manual de curl. Cabeceras que el navegador no deja cambiar: estándar Fetch (WHATWG). Bibliotecas: requests, net/http de Go y cURL de PHP. Para probarla, 45 comandos se enviaron a un servidor de prueba con curl 7.88 y con el código generado en Python 3.13 (requests), Node.js 24, Go 1.24 y PHP 8.3: llegaron el mismo método, la misma ruta, las mismas cabeceras y el mismo cuerpo, salvo en los casos que se explican arriba.