# アップロード

> POST /v1/upload で、Nodaro に画像、動画、オーディオをアップロードします。URL からのファイルのコピー、SNS 動画のインポート、保存済みメディアの無料トリミング、ライブラリの一覧取得もできます。

Source: https://nodaro.ai/ja/docs/developers/api/uploads

**アップロード**は、自分の画像、動画、オーディオを Nodaro のストレージに入れ、どのノードからも URL で使えるようにします。`POST /v1/upload` は、1 つのファイルを保存し、その URL を返します。ほかのルートは、URL からファイルをコピーしたり、SNS から動画をインポートしたり、保存済みのファイルを無料でカットしたり、保存しているメディアを一覧表示したりします。

## エンドポイント
| メソッド | パス | 説明 |
| --- | --- | --- |
| `POST` | `/v1/upload` | multipart form data として、1 つのファイルをアップロードします。 |
| `POST` | `/v1/save-to-storage` | URL からファイルを、ジョブとして自分のストレージにコピーします。 |
| `POST` | `/v1/download-video` | SNS、または動画への直接リンクから、動画をインポートします。 |
| `GET` | `/v1/download-video/progress/:downloadId` | インポートの進行状況を、サーバー送信イベントで返します。 |
| `POST` | `/v1/video-metadata` | ダウンロードせずに、動画の長さ、サイズ、タイトルを読み取ります。 |
| `POST` | `/v1/media/process` | 保存済みの動画またはオーディオファイルをトリミングまたはクロップします。無料で、同期的です。 |
| `GET` | `/v1/library` | 保存しているメディアを、ストレージの概要とともに返します。 |

## ファイルをアップロードする
ファイルは、`file` フィールドに multipart form data として送ります。`type` を `image`、`video`、`audio` のいずれかに設定して、一緒に送ることもできます。

**curl**

```bash
curl -s -X POST https://app.nodaro.ai/v1/upload \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -F "file=@portrait.png;type=image/png" \
  -F "type=image"
```

```json
{
"data": {
"url": "https://…/portrait.png",
"assetId": "5d6e7f80-91a2-4b3c-8d4e-5f60718293a4",
"thumbnailUrl": "https://…/portrait-thumb.webp",
"category": "image",
"filename": "portrait.png",
"mimeType": "image/png",
"sizeBytes": 1482233,
"r2Key": "…/portrait.png"
}
}
```

**TypeScript SDK**

```ts
// In a browser, file comes from an <input type="file">.
// In Node 20 or newer, build it from bytes:

const file = new File([await readFile('portrait.png')], 'portrait.png', { type: 'image/png' })
const upload = await client.uploads.upload(file)
console.log(upload.url) // pass it as imageUrl, videoUrl or audioUrl
```

| フィールド | 意味 |
| --- | --- |
| `url` | 保存されたファイルの公開 URL です。どのノードでも使えます。 |
| `assetId` | 自分のストレージにある、そのファイルの ID です。 |
| `thumbnailUrl` | 画像と動画のサムネイルです。オーディオでは `null` です。 |
| `category` | サーバーがファイルを分類した結果で、`image`、`video`、`audio` のいずれかです。 |
| `filename` | ファイルの表示名です。 |
| `mimeType` | サーバーが決定したファイルの種類です。下記を参照してください。 |
| `sizeBytes` | 保存されたサイズ（バイト）です。 |
| `r2Key` | ストレージ内での、そのファイルのキーです。 |

CLI には、アップロードのコマンドはありません。すでにオンラインにあるファイルをターミナルから自分のストレージにコピーするには、`nodaro media save <url>` を使います。

### 形式とファイルの種類
| メディア | 形式 |
| --- | --- |
| 画像 | PNG、JPEG、WebP |
| 動画 | MP4、MOV、WebM |
| オーディオ | MP3、WAV、M4A、AAC、OGG、WebM、FLAC。最大 50 MB です。 |

メディアの種類ごとに、それぞれのサイズ上限があります。クライアントが宣言する型は、標準的なものである必要はありません。サーバーは、ファイルを確認する前に、実際の型を判定するためです。

- **パラメーターは取り除かれます**。`audio/webm;codecs=opus` は `audio/webm` になります。
- **よくある別表記は変換されます**。Windows が単純な `.aac` ファイルに使う `audio/vnd.dlna.adts` は `audio/aac` に、`image/jpg` は `image/jpeg` に、`video/mov` は `video/quicktime` になります。
- **型が役に立たない場合は、ファイル名から判定されます**。`application/octet-stream` や、型がまったく指定されていない場合は、拡張子で決まります。`clip.mp4` は `video/mp4` として保存されます。

それでも受け付けている形式のどれにも一致しない場合は、受け付けている形式の一覧とともに `400 validation_error` が返されます。サーバーが決定した型は `mimeType` として返り、ファイルはその型で配信されます。

### アップロードが拒否される場合
| ステータス | コード | 意味 |
| --- | --- | --- |
| 400 | `validation_error` | ファイルが、受け付けている形式ではありません。 |
| 413 | | 自分のストレージが満杯です。SDK は、`limitBytes` に上限を含めた `StorageExceededError` をスローします。 |
| 422 | `upload_blocked` | デプロイメントのアップロードポリシーが、保存する前にファイルを拒否しました。`message` を、そのままユーザーに表示してください。このポリシーがあるデプロイメントだけで発生します。 |

## 代わりに URL を使う
ほとんどのルートは、`imageUrl`、`videoUrl`、`audioUrl`、`referenceImageUrls` などの URL でメディアを受け付けるため、すでにオンラインにあるファイルはアップロードする必要がありません。URL は、公開された `http` または `https` のアドレスである必要があります。非公開のネットワークアドレスを指す URL や、ほかのスキームを使う URL は拒否されます。

URL が一時的なもの、たとえば期限が切れる署名付きリンクである場合や、そのファイルを使い続けられるようにしたい場合は、ファイルを Nodaro のストレージにコピーしてください。

**curl**

```bash
curl -s -X POST https://app.nodaro.ai/v1/save-to-storage \
  -H "Authorization: Bearer $NODARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mediaUrl": "https://example.com/clip.mp4", "filename": "clip.mp4", "mediaType": "video"}'
# {"jobId":"…"}  poll the job; its output carries the stored file
```

**TypeScript SDK**

```ts
const { jobId } = await client.media.saveToStorage({
mediaUrl: 'https://example.com/clip.mp4',
filename: 'clip.mp4',
mediaType: 'video',
})
```

**CLI**

```bash
nodaro media save https://example.com/clip.mp4 --filename clip.mp4 --type video --watch
```

ワークフローの中では、アップロードしたファイルの URL を、実行の入力を通じて、[**画像アップロード**（Upload Image）](https://nodaro.ai/docs/nodes/image/upload-image)、[**動画アップロード**（Upload Video）](https://nodaro.ai/docs/nodes/video/upload-video)、[**オーディオアップロード**（Upload Audio）](https://nodaro.ai/docs/nodes/audio/upload-audio)のいずれかのノードに渡します。入力ノードのメディアの `url` フィールドは、実行のたびに、常に上書きできます。[新しい入力値でワークフローを実行する](https://nodaro.ai/docs/developers/api/workflows#run-a-workflow-with-new-input-values)を参照してください。

## SNS から動画をインポートする
`POST /v1/download-video` は、YouTube、TikTok、Instagram、X、Facebook から、または動画ファイルへの直接リンクから、動画を自分のストレージにインポートします。ジョブ ID ではなく、`downloadId` を返します。

```json
{ "url": "https://youtu.be/XXXX", "maxHeight": 720, "sectionStartSec": 30, "sectionEndSec": 90 }
```

- `maxHeight` は解像度を制限します。指定しない場合は、利用できる最高のものになります。`sectionStartSec` と `sectionEndSec` は、動画のその部分だけを取得します。両方とも送るか、どちらも送らないかのいずれかです。
- `requireAudio: false` を送らない限り、音声トラックのない動画は失敗します。
- 1 つのアカウントで、同時に実行できるインポートは 4 件までです。5 件目は `429 too_many_downloads` を返します。
- `GET /v1/download-video/progress/:downloadId` は、進行状況を、1 秒に約 2 回、サーバー送信イベントとしてストリーミングします。`{ phase, percent, videoUrl?, thumbnailUrl?, error? }` です。ストリームは、インポートが `completed`（保存された `videoUrl` 付き）または `failed`（`error` 付き）になると終了します。進行状況は、インポートの終了後、短い時間しか保持されないため、すぐに読み始めてください。
- 完成した動画は、自分のライブラリに保存されます。

インポートする前に動画を確認するには、`{ url }` を指定して `POST /v1/video-metadata` を呼び出します。ダウンロードせずに、長さ、サイズ、タイトルを読み取れます。ターミナルからは、`nodaro media download <url> --max-height 720 --watch` と `nodaro media metadata <url>` です。ほかのメディアツールは、[音声とメディア](https://nodaro.ai/docs/developers/api/voice-and-media)にあります。

## 保存済みファイルをトリミング・クロップする
`POST /v1/media/process` は、保存済みの動画またはオーディオファイルをカットまたはクロップします。無料で、ジョブを使わずに、すぐに応答します。

```json
{
"sourceUrl": "https://…/interview.mp4",
"type": "video",
"trim": { "startTime": 12.5, "endTime": 48 },
"crop": { "x": 0, "y": 0, "width": 1080, "height": 1080 }
}
```

応答は `{ "data": { url, thumbnailUrl, assetId, sizeBytes, mimeType, metadata } }` です。`format` は出力形式を指定します。動画は `mp4` または `webm`、オーディオは `mp3`、`wav`、`m4a`、`aac` です。`deleteSource: true` を指定すると、そのファイルが自分のものであり、ほかで使われていない場合、処理のあとに元のファイルが削除されるため、カットしたものが元のファイルを置き換えます。SDK では `client.media.process(input)` を呼び出します。ワークフローの中でトリミングするには、クレジットのかかる[**動画のトリミング**（Trim Video）](https://nodaro.ai/docs/nodes/video/trim-video)ノードを使います。

## 保存しているメディアを一覧表示する
`GET /v1/library` は、保存している画像、動画、オーディオを、ストレージの概要とともに返します。`type`（`image`、`video`、`audio` のいずれか）で絞り込み、`limit` と `cursor` でページ単位に分けて取得できます。SDK では `client.library.list({ type: 'image' })` を呼び出します。

## AI アシスタントからアップロードする
[MCP サーバー](https://nodaro.ai/docs/mcp/tools)は、アップロードの 3 つの方法を用意しており、それぞれ画像、オーディオ、動画に対応しています。すべて `assets:write` スコープが必要です。

| 方法 | ツール | 使える環境 |
| --- | --- | --- |
| チャット内のファイルピッカー | `upload_image_widget`、`upload_audio_widget`、`upload_video_widget` | Claude.ai のウェブ版です。画像のピッカーは、最大 10 ファイルまで扱えます。 |
| ブラウザーのアップロードページ | `request_image_upload`、`request_audio_upload`、`request_video_upload` | すべての MCP クライアントです。このツールは、ブラウザーで開くページと、ファイルの最終的な公開 URL を返します。 |
| 署名付きアップロード URL | `prepare_image_upload`、`prepare_audio_upload`、`prepare_video_upload` | Claude Code、Cursor、Cline など、シェルコマンドを実行できるクライアントです。`curl -X PUT --data-binary @file` でファイルを送ります。Claude.ai のウェブ版と Android では使えません。 |

## Frequently asked questions

### API で Nodaro にファイルをアップロードするには、どうすればよいですか？

POST /v1/upload に、file フィールドにファイルを入れた multipart form data を送ります。レスポンスには、保存されたファイルの url が含まれ、これをどのノードにも imageUrl、videoUrl、audioUrl として渡せます。

### アップロードできるファイル形式は何ですか？

画像は PNG、JPEG、WebP、動画は MP4、MOV、WebM、オーディオは MP3、WAV、M4A、AAC、OGG、WebM、FLAC です。オーディオファイルは、最大 50 MB です。

### ノードがファイルを使う前に、アップロードしておく必要がありますか？

いいえ。ほとんどのルートは、公開された http または https の URL を直接受け付けます。URL が非公開または一時的な場合や、Nodaro に独自のコピーを残しておきたい場合に、ファイルをアップロードするか、POST /v1/save-to-storage でコピーしてください。

### ストレージが満杯になると、どうなりますか？

アップロードは 413 を返し、SDK は limitBytes に上限を含めた StorageExceededError をスローします。不要になったファイルを削除するか、空き容量を確保してから、もう一度アップロードしてください。

### AI アシスタントは、MCP を通じてどのようにファイルをアップロードしますか？

MCP サーバーは、3 つの方法を用意しています。チャット内のファイルピッカー、ブラウザーのアップロードページ、そしてシェルコマンドを実行できるクライアント向けの、署名付きアップロード URL です。それぞれ、画像、オーディオ、動画に対応しています。
