Uploads
POST /v1/media/uploads stores an audio or image file on the account and returns its id up_….
Access: Keys with the media:generate scope, on an account with media access granted by Albastar Corp.
POST /v1/media/uploads stores an audio or image file on the key's account and returns an upload id up_…. An
upload is a voice reference in voice (speech), audio (transcription jobs) and from (POST /v1/media/voices),
and an image to start from in init_image (image jobs), for the account that uploaded the file only.
Parameters
Send the file as the raw request body, or as the part named file of a multipart/form-data body. The file is
WAV, MP3, M4A, Ogg, WebM or FLAC audio, or a PNG, JPEG or WebP image, 20 MB at most. The type is read from the
file's bytes; the Content-Type of a raw body is not used.
Request
The example downloads the reference clip of Narrator A, a synthetic voice, and uploads the clip as the raw body.
curl
curl -o reference.mp3 \
https://api.albastov.com/v1/media/samples/reference-848c3d555461736a.mp3
curl https://api.albastov.com/v1/media/uploads \
-H "Authorization: Bearer $ALBASTAR_API_KEY" \
-H "Content-Type: audio/mpeg" \
--data-binary @reference.mp3Python
import json
import os
import urllib.request
BASE = "https://api.albastov.com/v1"
UA = {"User-Agent": "my-app/1.0"}
req = urllib.request.Request(
f"{BASE}/media/samples/reference-848c3d555461736a.mp3", headers=UA
)
with urllib.request.urlopen(req, timeout=30) as res:
clip = res.read()
req = urllib.request.Request(
f"{BASE}/media/uploads",
data=clip,
headers={
**UA,
"Authorization": f"Bearer {os.environ['ALBASTAR_API_KEY']}",
"Content-Type": "audio/mpeg",
},
)
with urllib.request.urlopen(req, timeout=60) as res:
print(json.load(res)["id"])JavaScript
const base = "https://api.albastov.com/v1";
const clip = await fetch(
`${base}/media/samples/reference-848c3d555461736a.mp3`,
);
if (!clip.ok) throw new Error(`${clip.status} ${await clip.text()}`);
const res = await fetch(`${base}/media/uploads`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ALBASTAR_API_KEY}`,
"Content-Type": "audio/mpeg",
},
body: await clip.arrayBuffer(),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
console.log((await res.json()).id);Response
201 with the upload.
{
"id": "up_Q8mZr3kPwD5nTb7yXc2hLf",
"content_type": "audio/mpeg",
"bytes": 225068,
"sha256": "848c3d555461736aac50ca9009c56e9258fb6081a7724d21216923c9049212eb",
"created_at": "2026-11-03T04:02:58.117Z",
"source": null
}| Field | Value |
|---|---|
id | up_ and 22 random characters |
content_type | The type read from the file's bytes, such as audio/mpeg or image/png |
bytes | The file's size |
sha256 | The file's SHA-256, 64 hex characters |
created_at | RFC 3339 time |
source | null for a file sent to this route |
Errors
Errors have the shape {"ok": false, "error": "too-large", "code": "too-large", "message": "..."}.
| Status | Code | Meaning |
|---|---|---|
| 400 | bad-upload | The file did not arrive whole, or a multipart body has no part named file |
| 413 | too-large | The file is over 20 MB |
| 415 | not-an-image | The file is neither WAV, MP3, M4A, Ogg, WebM or FLAC audio nor a PNG, JPEG or WebP image: Upload a PNG, JPEG or WebP image, or WAV, MP3, M4A, Ogg, WebM or FLAC audio. |
not-an-image answers every file of another type, audio in another format included: the code is older than audio
uploads and keeps its name so that existing clients still match it. Branch on the status 415 or on the code.
Key, scope and rate-limit errors: Errors.