Saltar al contenido principal

Error 403 al descargar un vídeo de Veo: falta tu clave de API

La URI de vídeo que devuelve Veo en la API de Gemini exige tu clave; sin ella responde 403 PERMISSION_DENIED. Qué enviar desde SDK, curl, n8n o navegador.

LaoZhang AI TeamPublicado12 min de lectura
En esta página
Portada sobre el error 403 al descargar un vídeo de Veo en la API de Gemini: la misma URI responde 403 PERMISSION_DENIED sin clave y entrega video.mp4 con la cabecera x-goog-api-key

Has generado un vídeo con Veo a través de la API de Gemini, la operación ha terminado, la respuesta trae un video.uri y, al pedir esa dirección, recibes un 403. La causa casi nunca está en tu proyecto: esa URI no es un enlace público, sino un recurso de la API, y la petición de descarga tiene que llevar tu clave de API igual que la llevó la petición de generación. La documentación de Veo lo resuelve con la cabecera x-goog-api-key:

bash
curl -L -o video.mp4 -H "x-goog-api-key: $GEMINI_API_KEY" "${video_uri}"

Lo que cambia de un caso a otro es quién hace esa petición. Un cliente del SDK ya lleva la clave; un curl, un fetch o un nodo HTTP de n8n solo la llevan si la añades; una etiqueta de vídeo en el navegador no puede llevarla. Esto vale para el 403 que aparece al descargar: si el 403 llega al pedir la generación o al consultar el estado de la operación, el problema es otro y se trata más abajo.

Por qué la URI de tu propio vídeo responde 403 PERMISSION_DENIED

La dirección que devuelve la operación tiene esta forma:

https://generativelanguage.googleapis.com/v1beta/files/{ID}:download?alt=media

El dominio es el mismo que el de cualquier otra llamada a la API de Gemini, y se comporta igual: una petición sin identidad se rechaza antes de mirar de quién es el archivo. Que la URI haya salido de tu propia respuesta no la convierte en un enlace firmado ni temporal; es la ruta de un archivo que hay que pedir con credenciales.

En los hilos de 2025 del foro de desarrolladores de Google (96867, 106512, 85592) el mensaje que pegaban los afectados era este:

Generative Language API has not been used in project 542708778979 before or it is disabled.
Enable it by visiting https://console.developers.google.com/apis/api/generativelanguage.googleapis.com/overview?project=542708778979 then retry

con "status": "PERMISSION_DENIED" y reason: SERVICE_DISABLED en los detalles. El mensaje empuja a buscar el fallo en la consola, y ahí se pierde el tiempo: quienes lo recibieron confirman que 542708778979 no es ninguno de sus proyectos y que el mismo número aparece con usuarios y claves distintos. Habilitar la API en el proyecto propio, tocar IAM, regenerar la clave o pasar output_gcs_uri no les cambió nada. Google no explica en esos hilos de dónde sale ese número; la idea de que las peticiones sin clave se atribuyen a un proyecto por defecto de Google es una suposición de los usuarios del foro, no una declaración oficial.

Mark Daoust, que escribe en el hilo principal como mantenedor del SDK, lo dejó así el 23 de octubre de 2025: «Getting that error is "normal" when pasting the URL with no key into a web-browser. But it should not be coming back from ai.files.download». Es decir, pegar la URI en el navegador y recibir el error es el comportamiento esperado.

Qué devuelve el punto de descarga sin clave: 403 antes de buscar el archivo

Antes de los pasos, lo que se ha ejecutado y lo que no. Ejecutado: tres peticiones curl contra el punto de descarga con un identificador de archivo inventado, el 2 de octubre de 2026. No ejecutado: ninguna generación real con Veo ni ninguna descarga completada, por falta de una clave de la API de Gemini con facturación. La descarga correcta que describen las secciones siguientes procede de la documentación de Google y de usuarios del foro que confirman que les funcionó, no de una prueba propia.

Petición sin clave:

bash
curl -s "https://generativelanguage.googleapis.com/v1beta/files/abc123xyz000:download?alt=media"
json
{
  "error": {
    "code": 403,
    "message": "Method doesn't allow unregistered callers (callers without established identity). Please use API Key or other form of API consumer identity to call this API.",
    "status": "PERMISSION_DENIED"
  }
}

La misma petición con la ruta /download/v1beta/files/... devolvió idéntico 403. Con una clave no válida en x-goog-api-key, la respuesta cambia de código:

json
{
  "error": {
    "code": 400,
    "message": "API key not valid. Please pass a valid API key.",
    "status": "INVALID_ARGUMENT",
    "details": [
      { "reason": "API_KEY_INVALID", "domain": "googleapis.com" }
    ]
  }
}

(El bloque details está abreviado; el original incluye además el servicio y el mensaje localizado.)

De estas tres respuestas salen dos conclusiones útiles para diagnosticar:

  • El archivo abc123xyz000 no existe y aun así la respuesta sin clave es 403, no 404. El rechazo ocurre antes de buscar el archivo, así que ese 403 no dice nada sobre tu vídeo ni sobre tu proyecto.
  • El texto del mensaje sin clave ya no es el de los hilos de 2025: ahora habla de «unregistered callers» y no menciona ningún número de proyecto. Si ves cualquiera de los dos, la lectura es la misma: la petición llegó sin identidad.
Respuesta al pedir la URIQué indicaOrigen del dato
403 PERMISSION_DENIED, «Method doesn't allow unregistered callers…»La petición no lleva claveRespuesta registrada el 2 de octubre de 2026
403 PERMISSION_DENIED, SERVICE_DISABLED, proyecto 542708778979La petición no lleva clave (texto de 2025)Hilos del foro, mayo–septiembre de 2025
400 INVALID_ARGUMENT, API_KEY_INVALIDLa clave llega, pero está mal copiada o no existeRespuesta registrada el 2 de octubre de 2026

Lo que no figura en la documentación ni en estas pruebas: qué devuelve la descarga con una clave válida de un proyecto distinto al que generó el vídeo. La única referencia es una respuesta en el hilo 85592 del 13 de junio de 2025, «If you are using the same API key to generate and download the video, it should work». Usa la misma clave en las dos fases y te ahorras la incógnita.

¿En qué fase aparece tu 403? Generación, sondeo o descarga

Solo el 403 de la tercera fase se arregla añadiendo la clave a la descarga. Localiza primero la llamada que falla:

Llamada que devuelve 403Qué significaQué hacer
La petición de generación (generate_videos, predictLongRunning)La clave, sus restricciones o el proyecto rechazan la llamadaSigue la guía para corregir el 403 Permission Denied de la clave de Gemini API según dónde falla
El sondeo de la operación (operations.get)La operación se creó, pero consultar su estado se rechaza; aún no existe ninguna URICaso abierto sin solución conocida (ver más abajo)
La descarga de video.uriLa petición de descarga va sin claveLas cuatro secciones siguientes
La descarga de archivos de resultados de BatchOtro tipo de archivo, con un informe sin resolverCaso abierto (ver más abajo)

Las tres fases en las que puede aparecer el 403 con Veo, generación, sondeo y descarga: solo el de la descarga se corrige añadiendo la cabecera x-goog-api-key

Si todavía no tienes claro cómo encajan generación, sondeo y descarga en la operación de larga duración de Veo 3.1, la comparación de API y guía de migración de Sora 2 a Veo 3.1 recorre ese flujo paso a paso.

Descargar con el SDK en servidor: files.download con el mismo cliente

Si tu código corre en un servidor o en un script, deja que descargue el propio SDK: el cliente creado con tu clave hace la petición autenticada y no tienes que tocar la URI. Estos son los ejemplos de la documentación de Veo.

Python:

python
generated_video = operation.response.generated_videos[0]
client.files.download(file=generated_video.video, destination="dialogue_example.mp4")

JavaScript (Node):

javascript
await ai.files.download({
    file: operation.response.generatedVideos[0].video,
    downloadPath: "dialogue_example.mp4",
});

Go usa client.Files.Download(ctx, video.Video, nil).

Dos detalles del ejemplo de JavaScript. El primero: la muestra de la documentación llama a ai.files.download sin await; aquí se ha añadido porque el commit 127c9bf de js-genai, enlazado por Daoust el 24 de octubre de 2025, corrige precisamente que la escritura del archivo no se esperaba, y su descripción dice que, con el cambio, tras el await la escritura está completa. Ese fallo producía un archivo vacío o truncado, no un 403. El segundo: downloadPath escribe en el sistema de archivos local, así que es una llamada para Node, no para el navegador.

Quien abrió el hilo principal usaba ai.files.download desde Supabase Edge Functions (Deno) y no conseguía el archivo. El equipo del SDK dijo que no pudo reproducirlo y no consta que ninguna versión concreta del SDK lo provocara. Si te ocurre en un entorno parecido, pasa a la petición HTTP directa de la sección siguiente, que es lo que les funcionó a quienes lo comunicaron.

Descargar con curl o fetch: la cabecera x-goog-api-key

En una petición HTTP directa, la forma documentada es enviar la clave en la cabecera x-goog-api-key y seguir las redirecciones. El ejemplo REST de Google extrae la URI de la respuesta de la operación y la descarga así:

bash
video_uri=$(echo "${status_response}" | jq -r '.response.generateVideoResponse.generatedSamples[0].video.uri')

# Download the video using the URI and API key and follow redirects.
curl -L -o dialogue_example.mp4 -H "x-goog-api-key: $GEMINI_API_KEY" "${video_uri}"

El -L no es decorativo: el comentario de la propia documentación pide seguir redirecciones. La misma cabecera es la que usa el ejemplo para consultar el estado de la operación, de modo que si tu sondeo funciona, ya tienes la clave en el sitio correcto y solo falta repetirla en la descarga.

La solución aceptada en el hilo 96867 usa otra forma, con la clave como parámetro de la URL. Este código es el del foro, no el de la documentación:

javascript
const url = decodeURIComponent(generatedVideo.video.uri);
const res = await fetch(`${url}&key=${process.env.API_KEY}`);

Quien lo publicó cita como origen la muestra de Veo 3 en AI Studio, y al menos otros cuatro usuarios confirmaron que les funcionó, el último el 28 de abril de 2026. La documentación de Veo no recoge la forma ?key=, solo la cabecera. Entre las dos, la cabecera tiene una ventaja práctica: la clave no queda escrita en la URL, que es lo que suele acabar en registros de acceso y trazas de error. Reserva el parámetro para entornos donde no puedas fijar cabeceras.

Descargar desde n8n: la clave también en el nodo HTTP Request

En n8n el patrón del fallo es siempre el mismo: el nodo que genera y el que consulta el estado funcionan, y un nodo HTTP Request aparte pide la URI devuelta y recibe el 403. Ese tercer nodo es una petición nueva y no hereda nada de los anteriores.

Añade en el nodo de descarga la cabecera x-goog-api-key con la misma clave que usaste para generar, haz que siga redirecciones y que trate la respuesta como archivo binario, no como JSON. Lo mismo se aplica a cualquier herramienta sin código que tenga un paso HTTP genérico.

Estos pasos no se han ejecutado en n8n. Se apoyan en la forma documentada de la petición y en la respuesta del hilo 85592 citada arriba, que afirma que con la misma clave en generación y descarga debería funcionar.

Mostrar el vídeo en el navegador: la URI no sirve como src

Una etiqueta de vídeo o un enlace de descarga en una página no pueden enviar la cabecera x-goog-api-key, así que la URI de Veo puesta directamente en el atributo src siempre dará 403. Es lo que describe la incidencia 4025 de Genkit, abierta el 30 de diciembre de 2025 y aún sin cerrar a 2 de octubre de 2026: el complemento @genkit-ai/google-genai devuelve la URI tal cual como media.url, y la interfaz de desarrollo la carga en el navegador sin autenticar.

El parche que se propone ahí añade key= a la URL. En una herramienta local que solo ves tú puede valer; en una aplicación con usuarios, no: cualquier clave que llegue al navegador dentro de una URL queda a la vista de quien abra las herramientas de desarrollo. Tampoco hay alternativa oficial conocida. Un usuario pidió en el hilo 96867, el 30 de diciembre de 2025, una URL firmada utilizable desde el navegador («Exposing the API key in the URL isn't an option since end users need access»), y nadie le respondió.

Google no prescribe ninguna arquitectura en la documentación de Veo. Lo que se deduce de que la URI exija clave, de que el archivo caduque y de que no exista una URL firmada es este recorrido:

  1. Tu servidor descarga el vídeo con la clave (SDK o cabecera).
  2. Guarda los bytes en un almacenamiento que controles.
  3. El navegador recibe una URL de ese almacenamiento, con el control de acceso que tú decidas.

La clave no sale del servidor y el vídeo deja de depender del plazo de Google.

Comparación de dos recorridos: la URI de Veo puesta en el atributo src del navegador devuelve 403, mientras que el servidor descarga con la clave, guarda el vídeo en un almacenamiento propio y el navegador recibe una URL de ese almacenamiento

El archivo se elimina a los 2 días y reintentar un 403 no lo recupera

Descarga en cuanto termine la operación. Según la documentación de Veo, los vídeos generados se guardan en el servidor 2 días y después se eliminan; para conservar una copia hay que descargarla dentro de ese plazo. Los vídeos extendidos cuentan como recién generados, y usar un vídeo como referencia para una extensión reinicia su plazo de 2 días.

La documentación no indica qué código HTTP devuelve un archivo ya eliminado, y no hay ninguna prueba registrada de ese caso. Si una URI antigua falla aun con la clave correcta, comprueba primero la fecha de generación.

Poner la descarga en un bucle de reintentos tampoco ayuda. La guía de solución de problemas de la API de Gemini limita los reintentos a errores transitorios (429, 408 y 5xx) y dice expresamente: «Do not retry on client errors (like 400, 402, or 403)». Un 403 por falta de clave será 403 en todos los intentos, y mientras tanto corre el plazo de 2 días.

Cuándo añadir la clave no resuelve el 403

Añadir la clave resuelve la descarga de video.uri en la API de Gemini. Hay cuatro situaciones cercanas en las que no es la respuesta:

  • 403 en operations.get. Un informe del 29 de septiembre de 2026 en el hilo 185954 describe 6 de 6 operaciones de veo-3.1-generate-preview creadas correctamente con el SDK de Python google-genai 2.25.0 cuyo sondeo devuelve 403 PERMISSION_DENIED. A 2 de octubre de 2026 no tenía respuestas ni causa conocida. El fallo ocurre antes de que exista una URI, así que nada de lo anterior se aplica.
  • Archivos de resultados de Batch. Un usuario contó en el hilo 96867, el 24 de noviembre de 2025, que la descarga de resultados de la Batch API por /download/v1beta/files/... seguía dando permiso denegado tanto con la cabecera como con key=, aunque la misma clave funcionaba para consultar el estado. Es un único informe sin resolver, sobre otro tipo de archivo.
  • Vertex AI. La ruta de Vertex AI no devuelve esta URI. Según la referencia de Veo en Vertex AI, si la petición incluye storageUri la respuesta trae un gcsUri del tipo gs://BUCKET_NAME/TIMESTAMPED_FOLDER/sample_0.mp4; si no, el vídeo llega en base64 dentro de la respuesta (bytesBase64Encoded). Un gs:// es la ruta de un objeto de Cloud Storage, no un enlace HTTP, y leerlo depende de los permisos de quien llama sobre ese bucket.
  • Pasarelas y proxies de terceros. Si llamas a Veo a través de un intermediario, la URL que recibes, su caducidad y los motivos de un 403 son los de ese servicio. Los 2 días y la cabecera x-goog-api-key describen la API de Google; para lo demás manda la documentación del proveedor.

Preguntas frecuentes sobre el 403 al descargar vídeos de Veo

¿Qué es el proyecto 542708778979 que aparece en el error?

No es un proyecto tuyo. Los usuarios que recibieron ese mensaje en 2025 comprobaron que el número no correspondía a ninguno de sus proyectos y que se repetía con cuentas y claves distintas. Google no ha explicado su origen en esos hilos. A efectos prácticos, ver ese número significa que la petición de descarga llegó sin clave; no hay nada que habilitar en la consola.

La API ya está habilitada en mi proyecto, ¿por qué sigue el 403?

Porque el rechazo no depende de la configuración de tu proyecto, sino de que la petición de descarga no se identifica. Si la generación funcionó, la API está habilitada y la clave es válida. Lo que falta es enviar esa misma clave en la petición a video.uri, con la cabecera x-goog-api-key o a través de files.download del SDK.

¿Se puede obtener una URL pública o firmada del vídeo de Veo?

La documentación de Veo en la API de Gemini no describe ninguna, y la petición de una URL firmada en el foro sigue sin respuesta a 2 de octubre de 2026. Para compartir el vídeo, descárgalo en tu servidor y sírvelo desde tu propio almacenamiento. En Vertex AI el resultado puede escribirse directamente en un bucket de Cloud Storage con storageUri, pero esa es otra ruta de API, con otra autenticación.