# Veoの動画ダウンロードが403になる原因と直し方：APIキーを付ける

> Gemini APIでVeoが返す動画のURIは、キーなしで開くと403になります。生成に使ったAPIキーをヘッダーに付けて2日以内に保存し、ブラウザにはURIを直接渡しません。

- URL: https://blog.laozhang.ai/ja/posts/veo-video-download-403
- Published: 2026-10-02
- Updated: 2026-10-02
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ja/about)
- Category: APIガイド
- Tags: Veo, Gemini API, 403, PERMISSION_DENIED, 動画生成

---
Gemini APIでVeo（Googleの動画生成モデル）の生成が完了し、レスポンスに動画のURIが入っているのに、そのURIを開くと403が返る。この場合、原因はほぼ決まっていて、ダウンロードのリクエストにAPIキーが付いていません。`video.uri`に入っている`https://generativelanguage.googleapis.com/v1beta/files/{FILE_ID}:download?alt=media`は誰でも開ける共有リンクではなく、認証が必要なAPIリソースです。[公式ドキュメントのRESTサンプル](https://ai.google.dev/gemini-api/docs/veo)も、ダウンロードの行に`x-goog-api-key`ヘッダーを付けています。

直し方は、生成に使ったのと同じAPIキーをダウンロードのリクエストにも付けることです。どう付けるかは、リクエストを出す場所で変わります。

| ダウンロードする場所 | 取得方法 | 注意点 |
|---|---|---|
| サーバー側のSDK（Python、Node.js、Go） | APIキーで作ったクライアントの`files.download`を使う | URIを自分で取り出して別のHTTPクライアントで叩くと、キーが付かない |
| curlや素のHTTPリクエスト | `x-goog-api-key`ヘッダーを付け、リダイレクトを追従する | ポーリングと同じヘッダーをダウンロードにも付ける |
| n8nなどのHTTPノード | ダウンロード用のノードにも同じヘッダーを設定する | 生成用ノードの認証は、別ノードには引き継がれない |
| ブラウザのvideoタグやリンク | URIを直接渡さない。サーバーで保存し、自前のURLを渡す | タグはヘッダーを付けられず、URLにキーを付けると利用者に見える |

APIの有効化、IAMの変更、キーの作り直しでは、この403は消えません。エラー文に出てくるプロジェクト番号を探す必要もありません。理由は次の節のとおりです。

## 「project 542708778979」が出る403：キーなしのリクエストが原因

フォーラムで報告されているエラーは、HTTP 403、`"status": "PERMISSION_DENIED"`で、メッセージは次の形です。

```text
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
```

詳細には`reason: SERVICE_DISABLED`が付きます。メッセージどおりに読むと「自分のプロジェクトでAPIが無効になっている」と受け取れますが、`542708778979`は報告者の誰のプロジェクトでもありません。[Google AI Developers Forumのスレッド](https://discuss.ai.google.dev/t/96867)や[別のスレッド](https://discuss.ai.google.dev/t/106512)では、ユーザーもキーも違うのに同じ番号が出ています。報告は2025年5月〜9月、Veo 2とVeo 3.0のもので、環境はSupabase Edge Functions、Python（FastAPI、Django）、n8nのHTTP Requestノード、Node 22などです。

この番号がなぜ表示されるのかを、Googleはこれらのスレッドで説明していません。「キーのないリクエストがGoogle側の既定のプロジェクトに割り当てられる」という説明はフォーラム利用者の推測です。確かなのは次の2点です。

- 同じスレッドで[SDKのメンテナーとして回答しているMark Daoust氏](https://discuss.ai.google.dev/t/96867/16)が、2025年10月23日に「キーなしのURLをブラウザに貼ればそのエラーになるのは“普通”だが、`ai.files.download`から返ってくるはずはない」と書いています。
- 報告者たちは、自分のプロジェクトでのAPI有効化、IAMの変更、キーの再作成、`output_gcs_uri`の指定を試しましたが、どれも効きませんでした。解決として受け入れられたのは、ダウンロードのリクエストに自分のAPIキーを足す方法で、2025年8月、2025年9月、2026年4月に別のユーザーが「これで直った」と書き込んでいます。

スレッドの投稿者はこの現象を「Project Mismatch」と呼んでいますが、これは投稿者の付けた呼び名で、公式の診断名ではありません。コンソールでこの番号のプロジェクトを探しても見つからないのは、あなたの設定の問題ではないからです。

## キーなしは403、無効なキーは400：2026年10月2日のレスポンス

ここからは実際に送ったリクエストの結果です。実行したのは、存在しないファイルID（`abc123xyz000`）を使ったcurlのリクエスト3本です。実行していないのは、Veoでの実際の生成と、ダウンロードが成功するところまでの確認です。課金を有効にしたGemini APIキーがない環境だったため、成功する経路は公式ドキュメントとフォーラムの報告に基づいています。

| リクエスト | HTTPステータス | 本文 |
|---|---|---|
| キーなしで`/v1beta/files/abc123xyz000:download?alt=media`をGET | 403 | `PERMISSION_DENIED` |
| キーなしで`/download/v1beta/files/abc123xyz000:download?alt=media`をGET | 403 | 同じ本文 |
| 無効なキーを`x-goog-api-key`に入れて同じURLをGET | 400 | `INVALID_ARGUMENT`、reasonは`API_KEY_INVALID` |

キーなしの場合のレスポンスは次のとおりです。

```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"
  }
}
```

無効なキーの場合は、メッセージが`API key not valid. Please pass a valid API key.`に変わり、ステータスは400です。

![キーなしのGETは403のPERMISSION_DENIED、無効なキーは400のAPI_KEY_INVALID、生成と同じキーを付けると動画を保存できるという3つの分岐を並べた図](https://blog.laozhang.ai/posts/ja/veo-video-download-403/img/key-response-branches.webp)

この結果から読み取れることは3つあります。

1. ファイルIDが存在しなくても403が返るので、キーなしのリクエストはファイルを探す前に拒否されています。URIが正しいかどうか、動画が残っているかどうかとは関係がありません。
2. 2026年10月2日時点のメッセージは、2025年のスレッドにある`project 542708778979`の文面とは違います。どちらの文面でも、ステータスは403の`PERMISSION_DENIED`で、リクエストにキーがないことを指しています。手元のエラーが「unregistered callers」のほうでも、対処は同じです。
3. キーを付けたのに間違っている場合は、403ではなく400の`API_KEY_INVALID`になります。ダウンロードで403が出ているなら、まず疑うのは「キーが違う」ではなく「キーが届いていない」です。

## 実行環境別：動画のURIにAPIキーを付けて取得する

以下のコードは公式ドキュメントに載っている形か、フォーラム由来と明記したものです。前節のとおり、ダウンロード成功までの動作はこの環境では確認していません。

### Python・Node.js・GoのSDKではfiles.downloadを使う

SDKでは、APIキーを持ったクライアントがダウンロードも行います。URIを取り出して別のHTTPライブラリに渡す必要はありません。Pythonの公式サンプルは次の形です。

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

JavaScript（`@google/genai`）は次の形です。

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

公式サンプルは`ai.files.download`を`await`なしで呼んでいますが、ここでは`await`を付けています。`downloadPath`はローカルのファイルに書き出す引数なので、これはNode.jsなどサーバー側で動かす呼び出しです。ブラウザのコードには使えません。Goでは`client.Files.Download(ctx, video.Video, nil)`が同じ役割です。

SDKを使っているのに403になる、という報告もスレッドにはあります。Daoust氏は「チームでは再現できなかった」と書き、全員がSupabaseのDeno／Edge Functionsを使っているのかを尋ねています。翌日の2025年10月24日には、Node向けダウンローダーの修正コミット（[googleapis/js-genai@127c9bf](https://github.com/googleapis/js-genai/commit/127c9bf)）を紹介しました。ただしこのコミットが直したのは、`download()`を`await`した時点でファイルの書き込みが終わっていない問題で、空のファイルや途中で切れたファイルができる不具合です。403とは別の失敗で、SDKのいずれかのバージョンが403を起こしていたかどうかは分かっていません。この修正で403が直ったという書き込みもありません。

SDK経由で403が出る場合に確かめられるのは、クライアントに渡したキーが生成時と同じかどうかと、SDKを新しいバージョンに上げても変わらないかどうかです。それでも直らなければ、次のHTTPリクエストの形に切り替えると、キーが付いているかどうかを自分の目で確認できます。

### curlや素のHTTPリクエストではx-goog-api-keyヘッダーを付ける

公式のRESTサンプルは、完了したオペレーションのレスポンスからURIを取り出し、ヘッダーにキーを付けてダウンロードします。

```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}"
```

見落としやすいのは2点です。ポーリングで使ったのと同じヘッダーを、ダウンロードの行にも付けること。そして`-L`でリダイレクトを追従することです。ドキュメントのコメントも「URIとAPIキーを使い、リダイレクトを追従してダウンロードする」と書いています。`fetch`や`requests`など、ほかのHTTPクライアントでも同じヘッダーを付けます。

フォーラムで解決策として受け入れられたのは、ヘッダーではなくクエリにキーを足す書き方です。

```javascript
// Google AI Developers Forum のスレッド 96867 に投稿されたコード
const url = decodeURIComponent(generatedVideo.video.uri);
const res = await fetch(`${url}&key=${process.env.API_KEY}`);
```

URIにはすでに`?alt=media`が付いているので、`&key=`で足しています。投稿者は出どころを「AI StudioのVeo3サンプル」と書いています。この書き方は公式のVeoドキュメントには載っておらず、載っているのはヘッダーの形だけです。サーバー側のコードなら、公式ドキュメントどおりヘッダーを使うほうが、キーがURLに残りません。

### n8nなどのHTTPノードではダウンロード用ノードにも同じキーを設定する

n8nでの報告は、どれも同じ流れです。生成のリクエストとポーリングは成功し、そのあと別のHTTP Requestノードで返ってきたURIを取りにいくと403になります。認証は生成用のノードに設定しただけで、ダウンロード用のノードは何も付けずにURIへGETしているためです。

[フォーラムの回答](https://discuss.ai.google.dev/t/85592)（2025年6月13日）は「生成とダウンロードに同じAPIキーを使っていれば動くはず」としています。ダウンロード用のノードにも、ヘッダー名`x-goog-api-key`、値に生成と同じキーを設定してください。返ってくるのはJSONではなくMP4のデータなので、ノード側ではファイルとして受け取り、リダイレクトの追従も有効にします。HTTPリクエストを部品として組むほかのノーコードツールでも考え方は同じで、認証はリクエストごとに設定します。

### ブラウザのvideoタグやリンクにはURIを直接渡さない

videoタグの`src`やリンクの`href`にこのURIを入れると、ブラウザはヘッダーなしでGETするので403になります。タグには`x-goog-api-key`ヘッダーを付ける手段がありません。

実際に、Genkitの`@genkit-ai/google-genai`プラグインがこのURIをそのまま`media.url`として返し、Developer UIがvideoタグで読み込んで403になるという[Issue](https://github.com/genkit-ai/genkit/issues/4025)が2025年12月30日に立てられ、2026年10月2日時点でも未解決のままです。提案されている修正は、URLに`key=`を足すものです。

開発中に自分だけが見る画面なら、キー付きのURLでも用は足ります。利用者に届くページでは使えません。URLに付けたキーは、ページを開いた人がそのまま読めるからです。

## エンドユーザーに動画を見せるには：サーバーで保存して自前のURLを渡す

利用者に動画を見せるサービスでは、サーバー側でキーを付けてダウンロードし、ファイルを自前のストレージに置いて、そのストレージのURLを利用者に渡します。これはGoogleが定めている構成ではありません。公式ドキュメントのダウンロード手順、後述の保存期限、そしてキーをブラウザに出せないという制約から導いた提案です。

流れは次のとおりです。

1. サーバーでオペレーションの完了を確認し、前節のSDKまたはヘッダー付きのリクエストで動画を取得する。
2. 取得したデータを自分のストレージ（オブジェクトストレージなど）に保存する。
3. 利用者には、そのストレージが発行するURLを渡す。公開範囲や期限は自分のストレージ側で決める。

![動画のURIをブラウザに直接渡すと403になる経路と、サーバーでキーを付けて取得し自分のストレージに保存してそのURLを利用者に渡す3ステップを比べた図](https://blog.laozhang.ai/posts/ja/veo-video-download-403/img/server-side-delivery.webp)

「APIから署名付きURLや公開URLを直接もらえないか」という質問は、同じスレッドに2025年12月30日に投稿されています。投稿者は、利用者がアクセスするのでURLにキーを出すわけにはいかず、サーバーレス環境では一時保存も扱いにくい、と書いています。この質問には誰も回答していません。公式のVeoドキュメントにも、Gemini APIが署名付きURLを返すという記載はありません。

サーバーレス環境で一時ファイルを置きにくい場合は、ダウンロードのレスポンスをディスクに書かず、そのままストレージへのアップロードに流す形になります。その場合はSDKの`downloadPath`ではなく、ヘッダー付きのHTTPリクエストを自分で出します。

## 保存期限は2日：403をリトライせず、先にファイルを保存する

生成された動画がサーバーに残るのは2日間です。公式ドキュメントは「生成から2日以内にダウンロードしないとローカルに残せない」と明記しています。延長（extension）した動画は新しく生成したものとして扱われ、延長の元として参照された動画は2日のタイマーがリセットされます。

期限を過ぎたファイルにアクセスしたときに返るHTTPステータスは、公式ドキュメントに記載がなく、実際に試した結果もありません。分かっているのは、キーなしのリクエストはファイルの有無に関係なく403になる、という前節の結果だけです。キーを付けたうえで別のエラーが返るなら、生成からの経過時間を確認してください。

403が返ったときに同じリクエストを繰り返しても、結果は変わりません。[Gemini APIのトラブルシューティング](https://ai.google.dev/gemini-api/docs/troubleshooting)は、再試行するのは429、408、5xxなどの一時的なエラーだけで、400、402、403のようなクライアント側のエラーは再試行しないよう書いています。原因を直さないままリトライのループを回すと、その間に2日の期限だけが進みます。

動画がすでに課金済みで期限が迫っているなら、原因の調査より先に、キーを付けたcurlを1回実行してファイルを手元に保存するのが安全です。

## キーを付けても直らない403：ポーリングやBatchなど別の段階

ここまでの対処が当てはまるのは、生成が成功してURIを受け取り、そのURIを取りにいく段階で403になる場合です。どの段階で失敗したかで、原因も対処も変わります。

| 403が出た段階 | 状況 | 取るべき行動 |
|---|---|---|
| 生成リクエスト自体 | キーの制限、ブロックされたキー、APIの未有効化などの可能性 | 「[Gemini APIキーの403権限エラー：拒否された処理から直す手順](https://blog.laozhang.ai/ja/posts/gemini-api-key-permission-denied)」の切り分けに進む |
| ポーリング（`operations.get`） | URIがまだ存在しない段階での403 | 下記のとおり未解決の報告。キーを足す対処は当てはまらない |
| 動画のURIの取得 | キーなしのリクエスト | 生成と同じAPIキーをダウンロードのリクエストに付ける |
| Batch APIの結果ファイルの取得 | キーを付けても拒否されたという報告が1件 | 下記のとおり未解決 |

**ポーリングでの403。** 2026年9月29日に、`veo-3.1-generate-preview`のオペレーションは作成できるのに、`operations.get()`が403 `PERMISSION_DENIED`を返すという[報告](https://discuss.ai.google.dev/t/185954)が投稿されています。google-genai Python 2.25.0で、6件のオペレーションすべてで発生したという内容です。2026年10月2日時点で返信はなく、原因は分かっていません。1人のユーザーの報告で、ダウンロードの403とは別の段階の問題です。

**Batch APIの結果ファイル。** 2025年11月24日には、Batch APIの結果ファイルを`/download/v1beta/files/...`から取得する際、`x-goog-api-key`ヘッダーでも`key=`でも拒否されたという書き込みがあります。同じキーでステータスの取得はできていたそうです。Veoではなく別のエンドポイントの話で、これも解決していません。「キーを付ければ必ず通る」とは言い切れないことを示す例です。

**別のプロジェクトのキー。** 生成とダウンロードで違うキーを使っている場合は、生成に使ったキーに揃えてください。フォーラムの回答が「動くはず」としているのは、同じAPIキーを使う場合だけです。

**Vertex AI経由のVeo。** Vertex AIはそもそもこのURIを返しません。[Vertex AIのリファレンス](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo-video-generation)によると、リクエストに`storageUri`（`gs://BUCKET_NAME/SUBDIRECTORY`の形）を指定するとレスポンスに`gcsUri`が入り、指定しなければbase64でエンコードされた動画が`bytesBase64Encoded`として返ります。`gs://`で始まるURIはCloud Storageのオブジェクトのパスで、HTTPのリンクではありません。読み出すには、呼び出す側にCloud Storageへのアクセス権が必要です。逆に、Gemini API側に`output_gcs_uri`を渡しても、返ってきたのは`generativelanguage.googleapis.com`のURIのままだったという報告があります。

**サードパーティのAPIゲートウェイ経由。** Googleではない事業者のエンドポイントを通している場合、返ってくるURL、保存期間、403の原因はその事業者のものです。2日という期限や`x-goog-api-key`の扱いは、Googleのエンドポイントを直接呼んでいる場合の話なので、その事業者のドキュメントを確認してください。

Veo 3.1の生成からポーリング、ダウンロードまでの一連の流れを実装し直す場合は、「[Sora 2からVeo 3.1へ移行するには？APIの違いと実装手順](https://blog.laozhang.ai/ja/posts/sora-2-api-vs-veo-3-1)」で長時間実行オペレーションの扱いを確認できます。
