Skip to main content
The TUS resumable upload endpoint allows resumable and presigned uploads of video files. This enables end-users to upload directly to Bunny Stream and greatly improves reliability on poor networks and mobile connections. The endpoint uses the open TUS Protocol for resumable file uploads. Before a video can be uploaded through the TUS endpoint, a video object must be created through the Create Video API call to obtain the video ID.

TUS upload API endpoint

How it works

  1. Create a video object using the Create Video API to get a videoId.
  2. Generate a presigned signature on your server using SHA256.
  3. Upload the file from the client using a TUS client library with the presigned credentials.
This approach allows secure direct uploads from end-users without exposing your API key.

Authentication

To authenticate a TUS upload request, the following headers must be included:

Video metadata parameters

The following metadata can be passed with the TUS upload:

Generating the signature

The authorization signature is generated by hashing the concatenation of several values using SHA256:
The signature must be generated on your server to keep your API key secure. Never expose your API key in client-side code.
Put the upload routes behind your own authentication before you deploy. The create route makes a video in your library and hands back a signature that lets the caller upload into it. Left open, anyone who finds the URL can fill your library with uploads that you pay to store, encode, and deliver.Server Actions and API routes are public HTTP endpoints, even when nothing in your UI links to them. Check the user on every request, and check that they own a video ID before you re-sign it or return its status.
A 401 Unauthorized from the TUS endpoint means the AuthorizationSignature doesn’t match the headers the request sends, or the VideoId, AuthorizationSignature, or AuthorizationExpire header is missing. The values your server signs must match the headers the client sends byte-for-byte: library ID, API key, expiration, and video ID.A 400 Bad Request means AuthorizationExpire is already in the past, or LibraryId is missing or invalid. The response body says which.

Examples

Each framework guide signs the upload, sends the file, and plays the video once it’s encoded.

Laravel

Rails

Django

We have runnable apps for more stacks in BunnyWay/examples.

Next.js

Nuxt

SvelteKit

Uppy with React

Once you have the presigned credentials from your server, use a TUS client library to upload the file. The official tus-js-client is recommended for browser uploads. Install the TUS client:

Basic client-side upload

Next.js App Router

This example shows a complete implementation using Next.js with the App Router.

React with Express backend

Express server (server.js):
Set BUNNY_STREAM_API_KEY, BUNNY_STREAM_LIBRARY_ID, and APP_ORIGIN, the origin your React app runs on, such as http://localhost:5173. CORS only stops other websites from calling the API in a visitor’s browser. It doesn’t stop scripts, so the route still needs its own auth check.

Resuming uploads

One of the key benefits of TUS is the ability to resume interrupted uploads. Within a page session, tus-js-client retries failed requests and carries on from the last acknowledged chunk. To resume after a reload, upload into the same video again. A stored upload URL belongs to one video, so resuming it with another video’s credentials sends the bytes to the old video and leaves the new one empty. Save the video ID against the file, ask your server to re-sign that video instead of creating a new one, and only resume when the IDs match:
The framework upload guides and their examples on GitHub implement the full flow, including the server side.

Error handling

Implement proper error handling to provide a good user experience:
Ensure any AuthorizationExpire timestamp is at least 1 hour (3600 seconds) or longer to make sure uploads are completed before authorization expires.

Resumable (TUS) upload FAQ

Common questions about how authorization and resumability behave when uploading video with the TUS resumable protocol.
AuthorizationExpire is validated at the start of every POST, HEAD, and PATCH request - not only at upload creation. It is not rechecked during an active PATCH, so a chunk that is already streaming will not be interrupted mid-request if the signature expires while data is in flight.
Yes. The same video GUID can be re-signed and used to resume through the existing TUS upload URL - there is no need to create a new video object.Note that a newly generated signature does not extend the upload resource’s original expiry. Re-signing lets you continue an existing upload; it does not reset the clock on how long that upload remains available.
An incomplete upload remains resumable until the AuthorizationExpire value that was used when it was created, or after roughly 48 hours of inactivity - whichever comes first.Once it expires, requesting the upload returns 404 Not Found (not 410).
Last modified on October 6, 2026