> ## Documentation Index
> Fetch the complete documentation index at: https://bunnynet-cb9733c2-support-migration.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# HTTP

> Upload videos to Bunny Stream using the HTTP API.

From creating the video object to sending the actual video content, you’ll learn how to complete the process smoothly.

## What You’ll Need

Before you begin, ensure you have:

* A [bunny.net](https://bunny.net) account ([Log in](https://dash.bunny.net/auth/login?pk_buttonlocation=menu) or sign up for a [free trial](https://dash.bunny.net/auth/register)).

A video library already created. It can be done **via Dashboard** (Follow "Step 1" in the [Stream Quickstart](/stream/quickstart) to create a video library. An incorrect library ID will result in upload failure) or **via API** (use the "Add Video Library" HTTP call explained in the [Stream API Reference](/api-reference/stream) guide).

Have your Stream API key prepared. To learn how to obtain your Stream API key, see [Obtaining your Stream API key](/stream/authentication).

## Understanding the Upload Process

Uploading a video through the HTTP API involves **two main steps:**

1. **Create the video object** in your library (metadata and title).
2. **Upload the video file** in **binary format** using a PUT request.

## Creating a Video

Before uploading any video content, you must first **create a video object** in your library. This step is often overlooked, so please ensure it’s completed before proceeding with the upload.

> This step tells Bunny Stream that you’re about to upload a new video and gives it a title and optional metadata. It doesn’t upload the video yet, just sets up the “slot” for it.

You can find full details about the available parameters in the [Stream API Reference](/api-reference/stream).

## How to Create a Video:

Make an authenticated POST request to the following endpoint:

```bash theme={null}
POST https://video.bunnycdn.com/library/:libraryId/videos
```

**Headers:**

* `AccessKey`: Your **Stream API key**
* `Accept: application/json`
* `Content-Type: application/json`

**Body Parameters:**

* `title`: The name of your video. This will appear in the library UI.
* `collectionId` (optional): The ID of a collection in your library where this video should be placed.
* `thumbnailTime` (optional): The time (in milliseconds) to use when extracting the main video thumbnail.

**Example request:**

```bash theme={null}
curl --request POST
  --url https://video.bunnycdn.com/library/:libraryId/videos
  --header 'AccessKey: <Your Stream Library API key>'
  --header 'accept: application/json'
  --header 'content-type: application/json'
  --data '{"title":"test"}'
```

**Example Response:**

The response will return a new video object, including:

* A unique videoId (guid)
* The libraryId
* Basic metadata such as title and creation date

At this stage, most fields (like encoding status or view count) will be empty or zero since the file hasn’t been uploaded yet.

You’ll need the `videoId` from this response in the next step.

## Uploading the Video File

Once the video object is created, you can proceed to upload the actual video file.

Full API reference: [Stream API Reference](/api-reference/stream).

**Upload Endpoint:**

```bash theme={null}
PUT https://video.bunnycdn.com/library/{libraryId}/videos/{videoId}
```

**Required Parameters:**

libraryId: Your video library ID (retrieved as before).

videoId: The unique ID returned when you created the video object.

You can also find this ID in the Bunny dashboard under the “Video ID” field for any listed video.

**Example curl request:**

```bash theme={null}
curl --request PUT
  --url <https://video.bunnycdn.com/library/><Your Library ID>/videos/<Your Video ID>
  --header 'AccessKey: <Your Stream Library API key>'
  --header 'accept: application/json'
  --data-binary '@path/to/your/video.mp4'
```

**Example Response:**

```json theme={null}
{ "success": true, "message": "OK" }
```

This response indicates that the video was uploaded successfully.

<Note>
  A **401 Unauthorized** on create or upload usually means the `AccessKey` header is missing, contains a non-Stream key (e.g. an account-level API key), or is set against the wrong library — each Stream library has its own API key, found under Stream > Your Library > API. Upload calls authenticate per-library, so a key from a different library will be rejected even if it's valid.
</Note>

<Note>
  For files over **2 GB** or any upload over an unstable connection, prefer [TUS resumable uploads](/stream/tus-resumable-uploads) instead of this direct PUT. The HTTP API has no resume support — if the connection drops partway, the whole upload restarts. If a dashboard upload appears stuck, the "Uploading" state reflects your client's upload progress, not server-side processing; check your upload speed and try renaming the file before re-uploading to reset the upload context.
</Note>

**File Format Requirements:**

When uploading your video file, it must be sent as **raw binary data,** not encoded or wrapped in JSON.

Don’t base64 encode the file

Send the video as binary in the body of the request

**cURL Tip:**

Use the "--data-binary" flag to send the file correctly

```bash theme={null}
\--data-binary '@video.mp4'
```

If this step is skipped or misconfigured, the upload may silently fail or the video will not process correctly.

## Fetching Videos from a Remote URL (Optional)

If you already have a video file hosted on another platform or server, [bunny.net](https://bunny.net/) allows you to fetch it directly using a remote URL, saving you the trouble of downloading and re-uploading manually.

The documentation link to this can be found in the [Stream API Reference](/api-reference/stream).

<Info>
  The URL you provide must be accessible by bunny.net's fetch system. You can use the optional `headers` parameter to include custom HTTP headers with the fetch request, enabling authentication methods such as:

  * **Basic Authentication** (via the `Authorization` header)
  * **Static API keys** (via custom headers like `X-API-Key` or `Authorization: Bearer <token>`)

  However, more advanced authentication mechanisms such as signed URLs, expiring tokens, or time-limited access links are not supported, as the fetch is performed as a single server-side request and cannot handle dynamic token generation or multi-step authentication flows.

  See the [Fetch Video API Reference](/api-reference/stream/manage-videos/fetch-video) for details on the `headers` parameter.
</Info>

**Endpoint:**

```bash bash theme={null}
POST <https://video.bunnycdn.com/library/{libraryId}/videos/fetch>
```

**Example Request:**

```bash theme={null}
curl --request POST
  --url <https://video.bunnycdn.com/library/><Your Library ID>/videos/fetch
  --header 'AccessKey: <Your Stream Library API key>'
  --header 'accept: application/json'
  --header 'content-type: application/json'
  --data '{"url": "<https://example.com/video.mp4>"}'
```

Once fetched, the video will be automatically added to your library and begin processing like a normal upload.

### Queued Fetch Limit

The fetch API supports a limited number of queued fetch requests per user at a time; this limit may vary by region, time, current load, and other factors. If you exceed the limit before previous fetches complete, the API will return **HTTP 429 (Too Many Requests)**. To avoid this, either wait for in-progress fetches to finish before submitting new ones, or implement retry logic with backoff when you receive a 429 response.

<Info>
  Ensure any `AuthorizationExpire` timestamp is at least 1 hour (3600 seconds) or longer to make sure uploads are completed before authorization expires.
</Info>
