32blogby Studio Mitsu

Guía completa de curl: llamadas API, depuración y más

Aprende curl desde lo básico hasta lo avanzado: peticiones API, cabeceras, autenticación, transferencia de archivos y scripting.

by omitsu14 min read
Contenido

curl es la herramienta definitiva para comunicación HTTP desde la línea de comandos. curl URL envía un GET, -X POST -d '{...}' envía datos a una API, -v muestra la traza completa de la petición/respuesta — prácticamente cualquier operación HTTP en un solo comando.

¿Necesitas probar un endpoint de API desde la terminal? ¿Depurar una cadena de redirecciones? ¿Lanzar un webhook desde un script de CI?

curl lo maneja todo. Viene preinstalado en Linux y macOS, y funciona en Windows a través de WSL o Git Bash.

Esta guía cubre todo, desde lo básico hasta scripting del mundo real, con ejemplos listos para ejecutar.

¿Qué es curl?

curl (abreviatura de "Client URL") es una herramienta de línea de comandos para transferir datos usando URLs. Soporta más de 20 protocolos incluyendo HTTP, HTTPS, FTP, SFTP y SCP. Fue creado por Daniel Stenberg en 1998 y sigue siendo uno de los proyectos de código abierto con mantenimiento más activo.

Características clave:

  • Navaja suiza de HTTP: soporta GET, POST, PUT, DELETE, PATCH y todos los demás métodos
  • Salida flexible: obtén solo las cabeceras, solo el cuerpo, mide tiempos de respuesta o captura todo
  • libcurl: también disponible como biblioteca en C, utilizada por Python, PHP, Ruby y muchos otros lenguajes internamente
  • Multiplataforma: funciona en Linux, macOS y Windows

Cómo se compara con wget: wget está construido para descargar archivos — destaca en descargas recursivas y espejos de sitios. curl es la herramienta HTTP de propósito general — brilla en llamadas a API, inspección de respuestas y creación de peticiones complejas.

Para una comparación detallada, consulta la Guía completa de wget.

Uso básico

Verificar la instalación

Verifica que curl está disponible en tu sistema.

bash
curl --version

Si usas WSL (Windows Subsystem for Linux), la versión de Linux de curl está disponible. Git Bash también incluye curl. Ten en cuenta que el curl de PowerShell es un alias de Invoke-WebRequest — no es la misma herramienta.

bash
# WSL (Ubuntu)
sudo apt install curl

Petición GET

bash
curl https://example.com

El cuerpo de la respuesta se imprime en stdout. Para guardar en un archivo:

bash
# Guardar con un nombre personalizado
curl -o output.html https://example.com

# Guardar usando el nombre del archivo de la URL
curl -O https://example.com/file.zip

Inspeccionar cabeceras de respuesta

bash
# Solo cabeceras (petición HEAD)
curl -I https://example.com

# Cabeceras + cuerpo juntos
curl -i https://example.com

Modo verbose (depuración)

bash
curl -v https://example.com

Esto muestra la conversación completa: handshake TLS, cabeceras de petición, cabeceras de respuesta y cuerpo. Esencial para diagnosticar problemas de conexión.

Modo silencioso

bash
# Suprimir barra de progreso y mensajes de error
curl -s https://example.com

# Mostrar progreso como caracteres # (útil para archivos grandes)
curl -# -O https://example.com/file.zip

Referencia de opciones comunes

OpciónQué hace
-o ARCHIVOGuardar salida en ARCHIVO
-OGuardar usando el nombre de archivo de la URL
-I / --headObtener solo cabeceras (petición HEAD)
-iIncluir cabeceras de respuesta en la salida
-v / --verboseMostrar petición/respuesta completa (incluyendo TLS)
-s / --silentSuprimir progreso y errores
-L / --locationSeguir redirecciones
-X MÉTODOEspecificar método HTTP (POST, PUT, DELETE, etc.)
-H "Cabecera: Valor"Añadir cabecera personalizada
-d "datos"Enviar datos POST
-u usuario:contraseñaAutenticación básica
-k / --insecureOmitir verificación de certificado SSL
-c ARCHIVOGuardar cookies en ARCHIVO
-b ARCHIVOEnviar cookies desde ARCHIVO
--limit-rate VELOCIDADLimitar velocidad de transferencia (ej. --limit-rate 1M)
-w "formato"Formato de salida personalizado para info de respuesta
--connect-timeout SEGTimeout de conexión en segundos
-C -Reanudar descarga interrumpida
-F "clave=@archivo"Subir archivo como datos de formulario

Casos de uso reales

Llamadas REST API (GET / POST / PUT / DELETE)

Los patrones que más usarás al probar APIs.

Enviar datos JSON con POST:

bash
curl -s -X POST \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice", "email": "alice@example.com"}' \
  https://api.example.com/users

Autenticarse con un token Bearer:

bash
curl -s \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  https://api.example.com/me

Actualizar un recurso con PUT:

bash
curl -s -X PUT \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice Updated"}' \
  https://api.example.com/users/123

Eliminar un recurso:

bash
curl -s -X DELETE \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  https://api.example.com/users/123

Canalizar a jq para salida formateada:

bash
curl -s https://api.example.com/users | jq '.data[] | {id, name}'

Para más sobre procesamiento de salida JSON, consulta la Guía completa de jq.

Depuración de cabeceras y redirecciones

Inspeccionar el handshake TLS completo y cabeceras:

bash
curl -v https://example.com 2>&1 | head -30

La salida verbose va a stderr, así que 2>&1 la fusiona con stdout para canalizar a head.

Medir el desglose del tiempo de respuesta:

bash
curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" https://example.com

Esto muestra la resolución DNS, conexión TCP, handshake TLS y tiempo total por separado — ideal para identificar cuellos de botella de rendimiento.

Trazar la cadena de redirecciones:

bash
curl -s -L -o /dev/null -w "URL final: %{url_effective}\nRedirecciones: %{num_redirects}\n" https://example.com

Subida de archivos

Subir un archivo como datos de formulario:

bash
curl -F "file=@photo.jpg" https://api.example.com/upload

Subir múltiples archivos a la vez:

bash
curl -F "file1=@document.pdf" \
     -F "file2=@image.png" \
     -F "description=Monthly report" \
     https://api.example.com/upload

Especificar el tipo MIME explícitamente:

bash
curl -F "file=@data.csv;type=text/csv" https://api.example.com/import

Gestión de cookies

Mantener sesiones entre peticiones, como después de iniciar sesión.

bash
# Paso 1: Iniciar sesión y guardar cookies
curl -c cookies.txt \
  -d "username=admin&password=secret" \
  https://example.com/login

# Paso 2: Usar cookies guardadas para peticiones posteriores
curl -b cookies.txt https://example.com/dashboard

# Paso 3: Enviar cookies existentes y guardar las nuevas
curl -b cookies.txt -c cookies.txt https://example.com/profile

Reanudar descargas interrumpidas

Cuando una descarga grande se corta:

bash
# Descarga original (interrumpida por Ctrl+C, caída de red, etc.)
curl -O https://example.com/largefile.iso

# Reanudar desde donde se quedó
curl -C - -O https://example.com/largefile.iso

El flag -C - le dice a curl que auto-detecte el tamaño actual del archivo y solicite solo los bytes restantes.

Técnicas avanzadas

Simplificar llamadas JSON API con --json

El flag --json (curl 7.82+) condensa el patrón estándar de API JSON en una sola opción.

bash
# Enfoque tradicional (tres opciones necesarias)
curl -s -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"name": "Alice"}' \
  https://api.example.com/users

# --json lo hace todo en uno
curl -s --json '{"name": "Alice"}' https://api.example.com/users

--json internamente configura -d (POST), Content-Type: application/json y Accept: application/json. También lee desde archivos y stdin.

bash
# Enviar JSON desde un archivo
curl --json @payload.json https://api.example.com/users

# Pasar JSON por pipe
echo '{"status": "active"}' | curl --json @- https://api.example.com/users/123

Reintentos integrados con --retry

No necesitas escribir bucles de reintento en scripts — curl tiene --retry integrado.

bash
# Reintentar hasta 3 veces en errores transitorios (backoff automático)
curl --retry 3 --retry-delay 2 https://api.example.com/data

# Reintentar en todos los errores incluyendo 4xx/5xx
curl --retry 3 --retry-all-errors https://api.example.com/data

# Limitar el tiempo total de reintentos
curl --retry 5 --retry-max-time 60 https://api.example.com/data

Por defecto, curl reintenta en timeouts de conexión, HTTP 408, HTTP 429 y HTTP 5xx. Añade --retry-all-errors para incluir errores de red y otros fallos.

Peticiones paralelas (--parallel)

curl 7.66+ soporta --parallel (-Z) para peticiones concurrentes a múltiples URLs.

bash
# Solicitar 4 APIs en paralelo
curl -Z -s \
  -o users.json "https://api.example.com/users" \
  -o posts.json "https://api.example.com/posts" \
  -o comments.json "https://api.example.com/comments" \
  -o tags.json "https://api.example.com/tags"
bash
# Limitar conexiones concurrentes máximas
curl -Z --parallel-max 3 -s \
  -o file1.zip "https://example.com/file1.zip" \
  -o file2.zip "https://example.com/file2.zip" \
  -o file3.zip "https://example.com/file3.zip" \
  -o file4.zip "https://example.com/file4.zip" \
  -o file5.zip "https://example.com/file5.zip"

El valor por defecto de --parallel-max es 50. Ajústalo según los límites de tasa de la API.

Configuraciones reutilizables con -K

En lugar de escribir opciones largas cada vez, guárdalas en un archivo de configuración.

text
# ~/.curl/api-config
header = "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
header = "Content-Type: application/json"
header = "Accept: application/json"
silent
location
connect-timeout = 10
max-time = 30
bash
# Usar el archivo de configuración
curl -K ~/.curl/api-config https://api.example.com/users

# Archivo de configuración + opciones adicionales
curl -K ~/.curl/api-config --json '{"name": "Alice"}' https://api.example.com/users

Comparte archivos de configuración en el equipo para estandarizar los flujos de pruebas de API. Para ejecutar verificaciones de salud programadas, combínalo con cron / systemd timer.

Variables prácticas de -w

-w (--write-out) tiene variables útiles más allá del tiempo de respuesta.

bash
# Mostrar información detallada de la respuesta
curl -s -o /dev/null -w "\
HTTP/%{http_version} %{http_code}\n\
Size: %{size_download} bytes\n\
Content-Type: %{content_type}\n\
Connections: %{num_connects}\n\
IP: %{remote_ip}:%{remote_port}\n\
" https://example.com
text
HTTP/2 200
Size: 12345 bytes
Content-Type: text/html; charset=utf-8
Connections: 1
IP: 93.184.215.14:443
bash
# Salida en formato JSON (combinar con jq)
curl -s -o /dev/null -w '{
  "status": %{http_code},
  "time_total": %{time_total},
  "size": %{size_download},
  "ip": "%{remote_ip}"
}' https://example.com | jq '.'

Ejemplos de scripting

curl se combina naturalmente con scripts de shell. Para los fundamentos de scripting, consulta la Guía práctica de shell script.

Verificador de salud de APIs

Un script que comprueba el estado de múltiples endpoints e informa de fallos.

bash
#!/bin/bash

ENDPOINTS=(
  "https://api.example.com/health"
  "https://api.example.com/v2/status"
  "https://cdn.example.com/ping"
  "https://auth.example.com/health"
)

echo "=== Verificación de Salud de API ==="
echo ""

FAILED=0

for URL in "${ENDPOINTS[@]}"; do
  STATUS=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$URL")

  if [ "$STATUS" -ge 200 ] && [ "$STATUS" -lt 300 ]; then
    echo "[OK]   $STATUS  $URL"
  else
    echo "[FAIL] $STATUS  $URL"
    FAILED=$((FAILED + 1))
  fi
done

echo ""
echo "Resultados: $((${#ENDPOINTS[@]} - FAILED))/${#ENDPOINTS[@]} pasaron"

if [ "$FAILED" -gt 0 ]; then
  exit 1
fi

Descargador por lotes con reintentos

bash
#!/bin/bash

URLS=(
  "https://example.com/data/january.csv"
  "https://example.com/data/february.csv"
  "https://example.com/data/march.csv"
)

DEST_DIR="./downloads"
MAX_RETRIES=3

mkdir -p "$DEST_DIR"

for URL in "${URLS[@]}"; do
  FILENAME=$(basename "$URL")
  ATTEMPT=1

  while [ "$ATTEMPT" -le "$MAX_RETRIES" ]; do
    echo "Descargando $FILENAME (intento $ATTEMPT/$MAX_RETRIES)..."

    if curl -s -f -L -o "${DEST_DIR}/${FILENAME}" --connect-timeout 10 --max-time 120 "$URL"; then
      echo "  OK: $FILENAME"
      break
    else
      echo "  FALLÓ: $FILENAME"
      ATTEMPT=$((ATTEMPT + 1))

      if [ "$ATTEMPT" -le "$MAX_RETRIES" ]; then
        echo "  Reintentando en 5 segundos..."
        sleep 5
      fi
    fi
  done

  if [ "$ATTEMPT" -gt "$MAX_RETRIES" ]; then
    echo "  ABANDONADO: $FILENAME después de $MAX_RETRIES intentos"
  fi
done

echo "Hecho."

Consideraciones de seguridad

Actualizaciones de seguridad de curl

curl 8.19.0 (lanzado el 11 de marzo de 2026) es la versión más reciente. La anterior 8.18.0 (7 de enero de 2026) incluyó 6 correcciones de seguridad.

El programa de bug bounty de curl terminó a finales de enero de 2026. La avalancha de informes generados por IA hizo que la tasa de confirmación cayera por debajo del 5%, consumiendo recursos de triaje desproporcionados. Durante sus ~6 años de funcionamiento (desde abril de 2019), el programa confirmó 87 vulnerabilidades y pagó más de $100,000 en recompensas.

Nunca uses -k en producción

bash
# Solo para entornos de prueba con certificados autofirmados
curl -k https://self-signed.example.com/api

-k (--insecure) desactiva la verificación de certificados SSL. Está bien para probar con certificados autofirmados, pero usarlo en producción o scripts automatizados te expone a ataques man-in-the-middle.

Mantén las credenciales fuera de los comandos

bash
# Mal: contraseña visible en el historial del shell
curl -u admin:P@ssw0rd https://api.example.com/admin

# Bien: usar .netrc
echo "machine api.example.com login admin password P@ssw0rd" > ~/.netrc
chmod 600 ~/.netrc
curl -n https://api.example.com/admin

Siempre establece los permisos de .netrc a 600 para que otros usuarios no puedan leerlo.

Las variables de entorno también funcionan:

bash
curl -u "admin:${API_PASSWORD}" https://api.example.com/admin

Preguntas frecuentes (FAQ)

¿Cuándo debo usar curl vs wget?

curl destaca en llamadas API, depuración HTTP y creación de peticiones complejas. wget destaca en descargas recursivas y espejos de sitios. Para probar APIs, usa curl. Para descargas masivas de archivos, usa wget. Consulta la Guía práctica de wget para una comparación detallada.

¿Cuál es la forma más simple de enviar JSON con curl?

Con curl 7.82+, usa curl --json '{"key": "value"}' URL. El flag --json configura Content-Type, Accept y -d de una vez. En versiones anteriores, necesitas -X POST -H "Content-Type: application/json" -d '{...}'.

¿Cómo diagnostico respuestas lentas de curl?

Usa curl -o /dev/null -s -w "DNS: %{time_namelookup}s\nConnect: %{time_connect}s\nTLS: %{time_appconnect}s\nTotal: %{time_total}s\n" URL para medir la resolución DNS, conexión TCP, handshake TLS y tiempo total individualmente. Esto identifica en qué fase está el cuello de botella.

¿Es seguro usar curl -k (--insecure) en producción?

No. -k omite la verificación de certificados SSL, lo que te expone a ataques man-in-the-middle. Solo úsalo temporalmente en entornos de prueba con certificados autofirmados. En producción, usa certificados válidos o especifica un certificado CA con --cacert.

¿Cómo subo archivos con curl?

Usa curl -F "file=@nombre_archivo" URL para subidas como datos de formulario. Especifica tipos MIME con curl -F "file=@datos.csv;type=text/csv" URL. Añade múltiples flags -F para varios archivos.

¿Cómo evito que las contraseñas queden en el historial del shell?

Almacena las credenciales en un archivo .netrc y usa curl -n URL. Establece los permisos de .netrc con chmod 600. Las variables de entorno también funcionan: curl -u "user:${PASSWORD}" URL.

¿Cómo añado reintentos automáticos a curl?

Usa curl --retry 3 --retry-delay 2 URL para reintentos automáticos en errores transitorios. Añade --retry-all-errors para reintentar también en respuestas 4xx/5xx. No necesitas escribir bucles de reintento en tus scripts.

¿Cómo verifico mi versión de curl?

Ejecuta curl --version. La última versión está disponible en la página de descargas oficial de curl. A marzo de 2026, la más reciente es 8.19.0.

Artículos relacionados

Conclusión

curl es la navaja suiza de la comunicación HTTP. Ya sea que estés probando APIs, depurando conexiones, subiendo archivos o escribiendo flujos de trabajo automatizados, es la herramienta de referencia.

Referencia rápida de los patrones más útiles:

  • Petición básica: curl URL. Guardar en archivo: -o o -O
  • Llamadas API: --json '{...}' (7.82+) es lo más simple
  • Depuración: -v para traza completa, -w para tiempos de respuesta
  • En scripts: siempre usa -s -f para modo silencioso + detección de errores
  • Credenciales: usa .netrc o variables de entorno, nunca las pongas directamente en comandos
  • Mantente actualizado: revisa curl.se regularmente para nuevas versiones

Si tu necesidad principal es descargar archivos, wget es más sencillo para esa tarea. Para llamadas API, inspección de respuestas y trabajo HTTP complejo, curl es la elección clara. Usa ambos — cada uno tiene sus fortalezas.