La subida de archivos vía API es un requisito técnico común para los desarrolladores al llamar a interfaces de generación de vídeo por IA, procesamiento de imágenes, entre otras. En este artículo, explicaremos de forma sistemática el funcionamiento del método de codificación multipart/form-data, tomando como ejemplo la API de imagen a vídeo de Sora 2, para ayudarte a dominar esta habilidad fundamental.
Valor principal: Al terminar de leer este artículo, comprenderás por completo el mecanismo interno de multipart/form-data, aprenderás a usar el comando curl -F para subir archivos y podrás implementar por tu cuenta la subida de imágenes para APIs de IA como Sora 2.

Conocimientos fundamentales sobre la subida de archivos vía API
Antes de profundizar en el código, necesitamos entender por qué la subida de archivos por API requiere un método de codificación especial.
¿Por qué es necesario multipart/form-data?
Cuando envías datos de texto normales a través de una API, puedes usar la codificación simple application/x-www-form-urlencoded. Sin embargo, este método presenta problemas graves al manejar archivos:
| Tipo de codificación | Casos de uso | Capacidad de manejo de archivos | Eficiencia |
|---|---|---|---|
application/x-www-form-urlencoded |
Pares clave-valor simples | ❌ No apto | El binario requiere escape URL, baja eficiencia |
application/json |
Datos estructurados | ⚠️ Requiere codificación Base64 | El tamaño aumenta un 33% |
multipart/form-data |
Subida de archivos | ✅ Soporte nativo | Sin codificación, eficiente |
multipart/form-data es una solución propuesta en el estándar RFC 2388 de 1998, diseñada específicamente para resolver el problema de enviar texto y datos binarios de forma mixta en el protocolo HTTP.
Cómo funciona multipart/form-data
La idea central de multipart/form-data es dividir el cuerpo de una solicitud HTTP en múltiples "partes" (parts) independientes, donde cada parte puede tener su propio tipo de contenido.

Detalles de la estructura de datos
Una solicitud multipart/form-data típica contiene la siguiente estructura:
POST /v1/videos HTTP/1.1
Host: api.apiyi.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="prompt"
She turns around and smiles
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="model"
sora-2-pro
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="input_reference"; filename="sample.jpeg"
Content-Type: image/jpeg
[Datos binarios de imagen]
------WebKitFormBoundary7MA4YWxk--
| Componente | Función | Ejemplo |
|---|---|---|
| Boundary | Identificador único que separa las partes de los datos | ----WebKitFormBoundary7MA4YWxk |
| Content-Disposition | Metadatos que describen esa parte | form-data; name="prompt" |
| Content-Type | Tipo MIME de esa parte | image/jpeg |
| Body | Contenido de los datos reales | Datos de texto o binarios |
🎯 Punto técnico clave: El Boundary debe ser una cadena única que no aparezca en el cuerpo de la solicitud. El servidor utiliza este límite para analizar y separar cada una de las partes de los datos.
Guía detallada del comando curl -F: Subida de archivos a la API en la práctica
curl es la herramienta de línea de comandos más utilizada como cliente HTTP, y su parámetro -F está diseñado específicamente para peticiones multipart/form-data.
Sintaxis básica de curl -F
curl -F "nombre_del_campo=valor" URL
curl -F "campo_archivo=@ruta_del_archivo_local" URL
| Formato del parámetro | Descripción | Ejemplo |
|---|---|---|
-F "key=value" |
Envía un campo de texto normal | -F "prompt=Hola" |
-F "key=@file" |
Sube un archivo local | -F "[email protected]" |
-F "key=@file;type=mime" |
Especifica el tipo MIME del archivo | -F "[email protected];type=image/jpeg" |
-F "key=@file;filename=new.jpg" |
Personaliza el nombre del archivo subido | -F "[email protected];filename=subida.jpg" |
Diferencias entre curl -F y otros parámetros
Muchos desarrolladores suelen confundir el uso de -F, -d y -X POST:
# ❌ INCORRECTO: -d se usa para x-www-form-urlencoded, no es apto para subir archivos
curl -X POST -d "[email protected]" https://api.example.com/upload
# ❌ INCORRECTO: Especificar manualmente Content-Type pero usar -d
curl -X POST -H "Content-Type: multipart/form-data" -d "..." https://api.example.com/upload
# ✅ CORRECTO: Usar -F establece automáticamente el Content-Type y el boundary correctos
curl -F "[email protected]" https://api.example.com/upload
Nota técnica: Al usar
-F, curl automáticamente:
- Establece el método de petición como POST.
- Configura
Content-Type: multipart/form-data.- Genera un
boundaryúnico.- Formatea el cuerpo de la petición según el estándar RFC.
Sora 2 API: Subida de archivos en la práctica
Sora 2 es el modelo de generación de vídeo lanzado por OpenAI que permite subir imágenes de referencia a través de su API para generar vídeos. Este es un escenario típico de uso de multipart/form-data.
Parámetros de la API de Sora 2 (Imagen a Vídeo)
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
prompt |
string | ✅ | Texto descriptivo (indicación) del vídeo |
model |
string | ❌ | Selección de modelo: sora-2 o sora-2-pro |
size |
string | ❌ | Resolución: 1280x720, 720x1280, 1024x1792, 1792x1024 |
seconds |
integer | ❌ | Duración: 4, 8, 12 segundos |
input_reference |
file | ❌ | Imagen de referencia, usada como primer fotograma |

Comparativa de modelos Sora 2
| Característica | sora-2 | sora-2-pro |
|---|---|---|
| Calidad de generación | Buena | Excelente |
| Velocidad de renderizado | Más rápida | Más lenta |
| Uso recomendado | Prototipado rápido, pruebas | Salida de nivel de producción |
| Precio | Estándar | Más alto |
| Plataformas disponibles | APIYI apiyi.com, API oficial | APIYI apiyi.com, API oficial |
Ejemplo completo de subida con Sora 2
A continuación se muestra un ejemplo completo de cómo usar curl para llamar a la API de Sora 2 y generar un vídeo a partir de una imagen:
curl -X POST "https://api.apiyi.com/v1/videos" \
-H "Authorization: Bearer $APIYI_KEY" \
-H "Content-Type: multipart/form-data" \
-F prompt="She turns around and smiles, then slowly walks out of the frame." \
-F model="sora-2-pro" \
-F size="1280x720" \
-F seconds="8" \
-F input_reference="@sample_720p.jpeg;type=image/jpeg"
Desglose del comando
| Parte | Descripción |
|---|---|
curl -X POST |
Especifica el método de petición POST |
"https://api.apiyi.com/v1/videos" |
Endpoint de generación de vídeo de Sora 2 en APIYI |
-H "Authorization: Bearer $APIYI_KEY" |
Pasa la clave de API mediante una variable de entorno |
-H "Content-Type: multipart/form-data" |
Declara el tipo de contenido (curl -F lo añade automáticamente) |
-F prompt="..." |
La indicación (prompt) descriptiva del vídeo |
-F model="sora-2-pro" |
Selección del modelo de alta calidad |
-F size="1280x720" |
Resolución horizontal 720p |
-F seconds="8" |
Duración de 8 segundos |
-F input_reference="@sample_720p.jpeg;type=image/jpeg" |
Sube la imagen de referencia |
🚀 Inicio rápido: Te recomiendo usar la plataforma APIYI (apiyi.com) para probar rápidamente la API de Sora 2. Ofrece interfaces listas para usar que permiten la integración sin configuraciones complejas.
Puntos a tener en cuenta al subir imágenes
Al usar la API de Sora 2 para subir imágenes de referencia, ten en cuenta:
| Requisito | Descripción |
|---|---|
| Ajuste de resolución | La resolución de la imagen debe coincidir con el parámetro size del vídeo |
| Formatos compatibles | image/jpeg, image/png, image/webp |
| Tamaño de archivo | Se recomienda no exceder los 10MB |
| Calidad de imagen | Imágenes nítidas y con buena composición ofrecen mejores resultados |
Implementación de subida multipart/form-data en Python
Además de curl, en el desarrollo real es más común utilizar lenguajes de programación para realizar la subida de archivos. A continuación, se muestra cómo hacerlo con Python.
Ejemplo minimalista
import requests
# Uso de la interfaz unificada de APIYI
url = "https://api.apiyi.com/v1/videos"
headers = {"Authorization": "Bearer YOUR_API_KEY"}
# Preparación de datos multipart
files = {
"input_reference": ("sample.jpeg", open("sample_720p.jpeg", "rb"), "image/jpeg")
}
data = {
"prompt": "She turns around and smiles, then slowly walks out of the frame.",
"model": "sora-2-pro",
"size": "1280x720",
"seconds": "8"
}
response = requests.post(url, headers=headers, data=data, files=files)
print(response.json())
Ver código completo (incluye manejo de errores y sondeo)
import requests
import time
import os
class Sora2Client:
"""Cliente de la API de Sora 2 - Soporta subida de archivos multipart/form-data"""
def __init__(self, api_key: str, base_url: str = "https://api.apiyi.com/v1"):
self.api_key = api_key
self.base_url = base_url
self.headers = {"Authorization": f"Bearer {api_key}"}
def create_video(
self,
prompt: str,
model: str = "sora-2",
size: str = "1280x720",
seconds: int = 8,
input_reference: str = None
) -> dict:
"""
Crear tarea de generación de video
Args:
prompt: descripción del video (indicación)
model: selección de modelo (sora-2 o sora-2-pro)
size: resolución
seconds: duración (4, 8, 12)
input_reference: ruta de la imagen de referencia (opcional)
Returns:
Diccionario con la información de la tarea
"""
url = f"{self.base_url}/videos"
data = {
"prompt": prompt,
"model": model,
"size": size,
"seconds": str(seconds)
}
files = None
if input_reference and os.path.exists(input_reference):
# Determinar el tipo MIME según la extensión del archivo
ext = os.path.splitext(input_reference)[1].lower()
mime_types = {
".jpg": "image/jpeg",
".jpeg": "image/jpeg",
".png": "image/png",
".webp": "image/webp"
}
mime_type = mime_types.get(ext, "application/octet-stream")
files = {
"input_reference": (
os.path.basename(input_reference),
open(input_reference, "rb"),
mime_type
)
}
try:
response = requests.post(
url,
headers=self.headers,
data=data,
files=files,
timeout=30
)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
return {"error": str(e)}
finally:
if files and "input_reference" in files:
files["input_reference"][1].close()
def get_video_status(self, video_id: str) -> dict:
"""Consultar el estado de generación del video"""
url = f"{self.base_url}/videos/{video_id}"
response = requests.get(url, headers=self.headers, timeout=30)
return response.json()
def wait_for_completion(self, video_id: str, poll_interval: int = 10) -> dict:
"""Sondeo (polling) para esperar a que se complete la generación del video"""
while True:
status = self.get_video_status(video_id)
if status.get("status") in ["completed", "failed"]:
return status
print(f"Status: {status.get('status')}... esperando {poll_interval}s")
time.sleep(poll_interval)
# Ejemplo de uso
if __name__ == "__main__":
client = Sora2Client(api_key=os.getenv("APIYI_KEY"))
# Crear tarea de imagen a video
result = client.create_video(
prompt="She turns around and smiles, then slowly walks out of the frame.",
model="sora-2-pro",
size="1280x720",
seconds=8,
input_reference="sample_720p.jpeg"
)
if "id" in result:
print(f"Tarea creada: {result['id']}")
final_result = client.wait_for_completion(result["id"])
print(f"URL del video: {final_result.get('video_url')}")
else:
print(f"Error: {result}")
Sugerencia: Obtén cuota de prueba gratuita en APIYI (apiyi.com) para validar rápidamente la función de imagen a video.
Manejo de multipart en la librería requests
Puntos clave para manejar multipart/form-data con la librería requests de Python:
| Parámetro | Uso | Descripción |
|---|---|---|
data |
Campos normales del formulario | Formato de diccionario: {"key": "value"} |
files |
Campos de archivo | Formato de tupla: {"name": (filename, file_obj, content_type)} |
⚠️ Nota: Al usar simultáneamente los parámetros
datayfiles,requestsconfigurará automáticamente elContent-Typey elboundarycorrectos; no es necesario especificarlos manualmente.
Solución en JavaScript/Node.js
Entorno de navegador (API FormData)
const formData = new FormData();
formData.append('prompt', 'She turns around and smiles');
formData.append('model', 'sora-2-pro');
formData.append('size', '1280x720');
formData.append('seconds', '8');
formData.append('input_reference', fileInput.files[0]);
fetch('https://api.apiyi.com/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
// Nota: NO establezcas manualmente el Content-Type
},
body: formData
})
.then(response => response.json())
.then(data => console.log(data));
Entorno Node.js
const FormData = require('form-data');
const fs = require('fs');
const axios = require('axios');
const form = new FormData();
form.append('prompt', 'She turns around and smiles');
form.append('model', 'sora-2-pro');
form.append('size', '1280x720');
form.append('seconds', '8');
form.append('input_reference', fs.createReadStream('sample_720p.jpeg'), {
contentType: 'image/jpeg'
});
axios.post('https://api.apiyi.com/v1/videos', form, {
headers: {
...form.getHeaders(),
'Authorization': 'Bearer YOUR_API_KEY'
}
})
.then(response => console.log(response.data));
💡 Consejo clave: Al usar
FormDataen el navegador, no configures manualmente el encabezadoContent-Type. El navegador agregará automáticamente el parámetroboundarycorrecto.
Solución de problemas comunes de multipart/form-data
Causas comunes de fallos en la carga
| Problema | Síntoma | Solución |
|---|---|---|
| Falta el boundary | El servidor devuelve 400 | No configures el Content-Type manualmente, deja que la herramienta lo genere automáticamente |
| Error en el tipo MIME | Archivo rechazado | Usa ;type=image/jpeg para especificarlo claramente |
| Ruta de archivo incorrecta | No se encuentra el archivo | Asegúrate de que la ruta tras el @ sea correcta; soporta rutas relativas/absolutas |
| Resolución no coincidente | Error en la API de Sora | La resolución de la imagen debe coincidir con el parámetro size |
| Archivo demasiado grande | Tiempo de espera agotado o rechazado | Comprime la imagen o usa carga por fragmentos |
Consejos de depuración
Usa el parámetro -v de curl para ver la solicitud completa:
curl -v -F "[email protected]" https://api.example.com/upload
Esto mostrará:
- Encabezados de la solicitud (incluyendo el Content-Type y boundary autogenerados)
- Estructura del cuerpo de la solicitud
- Respuesta del servidor
Preguntas frecuentes
Q1: ¿Qué es mejor: multipart/form-data o codificación Base64?
multipart/form-data es más adecuado para cargar archivos. La codificación Base64 aumenta el tamaño del archivo aproximadamente un 33%, lo que incrementa el tiempo de transmisión de red y la carga de procesamiento del servidor. multipart/form-data transmite datos binarios directamente, lo que resulta en una mayor eficiencia.
Sin embargo, en ciertos escenarios (como WebSockets o APIs JSON de un solo campo), Base64 puede ser la única opción. Al llamar a APIs a través de la plataforma APIYI (apiyi.com), priorizar el uso de multipart/form-data te brindará un mejor rendimiento.
Q2: ¿Por qué falla mi carga con curl -F?
Las causas comunes incluyen:
- Problemas con la ruta del archivo: Asegúrate de que el símbolo
@vaya seguido de la ruta correcta del archivo. - Problemas de permisos: Revisa los permisos de lectura del archivo.
- Tipo MIME: Algunas APIs requieren que se especifique el content-type correcto.
Se recomienda validar primero el formato de la solicitud en el entorno de pruebas de APIYI (apiyi.com); la plataforma ofrece mensajes de error detallados para ayudarte a localizar el problema rápidamente.
Q3: ¿Qué formatos de imagen soporta la API de Sora 2?
La API de Sora 2 admite los siguientes formatos de imagen para input_reference:
- JPEG (
.jpg,.jpeg): Recomendado, buena tasa de compresión. - PNG (
.png): Soporta canales de transparencia. - WebP (
.webp): Formato moderno, tamaño de archivo pequeño.
La resolución de la imagen debe coincidir con el parámetro size del vídeo de destino. Por ejemplo, si usas una resolución de 1280x720, la imagen de referencia también debe ser de 1280×720.
Q4: ¿Cómo manejar la carga de archivos grandes?
Para archivos grandes, puedes considerar:
- Carga por fragmentos: Dividir el archivo en trozos pequeños y subirlos secuencialmente.
- Optimización por compresión: Comprimir el archivo manteniendo la calidad necesaria.
- Reanudación de carga: Implementar soporte para continuar la subida desde el punto donde falló.
multipart/form-data admite la transmisión por flujo (streaming), lo que permite al servidor procesar los datos mientras los recibe, siendo ideal para escenarios de archivos de gran tamaño.
Resumen
Este artículo detalla la tecnología central para la carga de archivos en API: multipart/form-data.
Repaso de puntos clave:
| Punto clave | Descripción |
|---|---|
| Principio de codificación | El boundary separa los datos en varias partes; cada parte tiene su propio Content-Type independiente. |
Comando curl -F |
-F "key=value" envía texto, -F "key=@file" carga un archivo. |
| Práctica con Sora 2 | Uso del parámetro input_reference para subir imágenes de referencia; la resolución debe coincidir. |
| Implementación en varios lenguajes | Uso de requests en Python o FormData en JavaScript. |
| Consejos de depuración | Usar curl -v para visualizar la solicitud completa. |
Dominar multipart/form-data es una habilidad fundamental para el desarrollo con APIs de IA. Ya sea para la generación de video con Sora 2, la comprensión de imágenes con GPT-4 Vision o cualquier otra API que requiera la carga de archivos, los principios básicos son los mismos.
Te recomendamos usar APIYI (apiyi.com) para validar rápidamente la función de carga de archivos y experimentar con una interfaz de API unificada y soporte técnico detallado.
Autor: Equipo APIYI | Especialistas en compartir tecnología de APIs de Modelos de Lenguaje Grande
Intercambio técnico: Visita apiyi.com para obtener más recursos de desarrollo de APIs.
Referencias
-
RFC 2388: Especificación estándar de multipart/form-data
- Enlace:
tools.ietf.org/html/rfc2388
- Enlace:
-
Documentación oficial de curl: Multipart Formposts
- Enlace:
everything.curl.dev/http/post/multipart
- Enlace:
-
MDN Web Docs: Uso de objetos FormData
- Enlace:
developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest_API/Using_FormData_Objects
- Enlace:
-
Documentación de la API de OpenAI Sora: Guía de generación de video
- Enlace:
platform.openai.com/docs/guides/video-generation
- Enlace:
