Uploading
Uploading a video is always the same three calls: create the video record, upload the file straight to storage with the URL that call returns, then tell the API the upload is complete so it can start transcoding. Below is a runnable version of that flow in cURL, Node, and Python, using a small sample video so you can copy, paste, and see a real video come back.
- cURL
- Node
- Python
This needs jq installed to pull fields out of the
JSON responses.
export HS_KEY=paste-your-key-here
curl -sL https://hyperserve.io/demo.mov -o sample.mov
V=$(curl -s -X POST https://api.hyperserve.io/api/video \
-H "X-API-KEY: $HS_KEY" -H "Content-Type: application/json" \
-d '{"filename":"sample.mov","resolutions":["480p"],"isPublic":true}')
curl -s -X PUT "$(echo "$V" | jq -r .uploadUrl)" \
-H "Content-Type: $(echo "$V" | jq -r .contentType)" \
--data-binary @sample.mov
curl -s -X POST "https://api.hyperserve.io/api/video/$(echo "$V" | jq -r .id)/complete-upload" \
-H "X-API-KEY: $HS_KEY"
npm install @hyperserve/hyperserve-js
curl -sL https://hyperserve.io/demo.mov -o sample.mov
import { readFileSync } from "node:fs";
import { HyperserveClient } from "@hyperserve/hyperserve-js";
const client = new HyperserveClient({ apiKey: process.env.HYPERSERVE_API_KEY });
const { id, uploadUrl, contentType } = await client.createVideo({
filename: "sample.mov",
resolutions: ["480p"],
isPublic: true,
});
// In a browser, use putVideoToStorage from @hyperserve/hyperserve-js/browser.
await fetch(uploadUrl, {
method: "PUT",
headers: { "Content-Type": contentType },
body: readFileSync("sample.mov"),
});
await client.completeUpload(id);
There is no Python SDK yet, so this calls the REST API directly.
# pip install requests
import os
import requests
API = "https://api.hyperserve.io/api"
API_KEY = os.environ["HYPERSERVE_API_KEY"]
# Download the sample video
with open("sample.mov", "wb") as f:
f.write(requests.get("https://hyperserve.io/demo.mov").content)
with open("sample.mov", "rb") as f:
file_bytes = f.read()
create = requests.post(
f"{API}/video",
headers={"X-API-KEY": API_KEY, "Content-Type": "application/json"},
json={
"filename": "sample.mov",
"resolutions": ["480p"],
"isPublic": True,
},
).json()
requests.put(
create["uploadUrl"],
headers={"Content-Type": create["contentType"]},
data=file_bytes,
)
requests.post(
f"{API}/video/{create['id']}/complete-upload",
headers={"X-API-KEY": API_KEY},
)
Waiting for the video
complete-upload queues transcoding, it does not finish it. Poll the
top-level status field on
Get public video or
Get private video until it
reads ready or fail. Entries in resolutions appear one at a time as each
one finishes, so an empty or partial resolutions object while status is
processing is normal, not a failure. To skip polling entirely, have us call
you instead: see the webhook guide.
Next steps
If you use an AI coding agent, Integrate with AI will wire this into your own project instead of a standalone sample. See File limits for the size and format ceilings the upload is checked against.