Subir archivos
Convierte un archivo local en una URL pública que FFHub pueda leer.
Los workers de FFHub se ejecutan en la nube y solo aceptan entradas que sean URLs públicas. Si tu archivo está en tu laptop, en tu teléfono o en un bucket privado, primero súbelo al almacenamiento de FFHub y pasa la URL devuelta a tu comando ffmpeg.
Cómo funciona la subida
Son dos pasos, y el archivo nunca pasa por nuestros servidores. Tu cliente obtiene una URL firmada de un solo uso y hace PUT directamente a R2.
- Firmar.
POST /v1/uploads/signdevuelve una URL prefirmada válida por 15 minutos. - PUT. Sube los bytes a esa URL con
curl,fetcho cualquier cliente HTTP.
Esto te permite subir archivos de hasta 5 GB sin que nuestros servidores intervengan en la transferencia de datos.
Paso 1 — Obtén una URL firmada
curl -X POST https://api.ffhub.io/v1/uploads/sign \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "input.mp4",
"size": 12345678,
"content_type": "video/mp4"
}'
Respuesta:
{
"upload_url": "https://...r2.cloudflarestorage.com/...?X-Amz-Signature=...",
"public_url": "https://storage.ffhub.io/tmp/uploads/<user>/<rand>.mp4",
"key": "tmp/uploads/<user>/<rand>.mp4",
"content_type": "video/mp4",
"expires_at": "2026-05-12T05:30:00Z"
}
Paso 2 — Sube el archivo
curl -fsS -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary "@./input.mp4"
El encabezado Content-Type debe coincidir exactamente con el content_type que enviaste en el paso 1 — R2 rechaza la firma si no coincide.
Un PUT fallido pasa desapercibido con facilidad: sin -f, curl termina con código 0 incluso ante un 403, y te quedas con una public_url que no tiene ningún archivo detrás. La tarea que envíes después fallará con HTTP Error 404: Not Found sobre una URL que parece perfectamente válida. Comprueba siempre que el PUT haya funcionado antes de enviar una tarea.
Una vez que el PUT devuelva 200/204, el campo public_url del paso 1 ya estará disponible para lectura.
Ejemplo completo de principio a fin
FILE=./input.mp4
SIZE=$(stat -f%z "$FILE" 2>/dev/null || stat -c%s "$FILE")
# 1. Firmar
SIGNED=$(curl -s -X POST https://api.ffhub.io/v1/uploads/sign \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"filename\":\"input.mp4\",\"size\":$SIZE,\"content_type\":\"video/mp4\"}")
UPLOAD_URL=$(echo "$SIGNED" | jq -r '.upload_url')
PUBLIC_URL=$(echo "$SIGNED" | jq -r '.public_url')
# 2. Subir directamente a R2
curl -fsS -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary "@$FILE" || { echo "Fallo al subir el archivo"; exit 1; }
# 3. Enviar una tarea usando public_url como entrada
curl -X POST https://api.ffhub.io/v1/tasks \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d "{\"command\":\"-i $PUBLIC_URL -c:v libx264 -crf 28 output.mp4\"}"
El CLI hace todo este proceso automáticamente — consulta CLI.
Límites
- Tamaño máximo: 5 GB por subida (límite de single-PUT en R2)
- Validez de la URL firmada: 15 minutos a partir de
expires_at; vuelve a firmar si se vence - Tiempo de vida del archivo: 7 días, luego se elimina de R2
Si necesitas conservar los archivos más de 7 días, cópialos a tu propio bucket en cuanto la tarea finalice.
¿Ya tienes una URL pública?
Omite todo el flujo. La API de tareas acepta cualquier URL pública como entrada -i:
curl -X POST https://api.ffhub.io/v1/tasks \
-H "Authorization: Bearer $FFHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"command":"-i https://example.com/clip.mp4 -c:v libx264 output.mp4"}'
Tu S3, tu CDN, nuestro almacenamiento — todos son equivalentes. Al módulo de tareas no le importa dónde vivan los bytes.