Uploading files

guide · updated 2026-08-19

There are two ways to get a file in: a single multipart request for anything under 500 MB, and a resumable session for larger files or flaky connections. Both end with the same file object.

Single request

curl -X POST https://api.media-host.online/v1/files \
  -H "Authorization: Bearer $MH_TOKEN" \
  -F "file=@ep-048-final.mp3" \
  -F "collection=weekly-show" \
  -F "title=048 — The slow season" \
  -F "published_at=2026-08-21T06:00:00Z"

The response is returned once the bytes are stored. Duration, bitrate and loudness are filled in a few seconds later by the processing worker; until then state is processing.

{
  "id": "f_7Q2kd9Lm",
  "collection": "weekly-show",
  "filename": "ep-048-final.mp3",
  "bytes": 58213904,
  "content_type": "audio/mpeg",
  "state": "processing",
  "url": "https://cdn.media-host.online/weekly-show/ep-048-final.mp3",
  "created_at": "2026-08-19T14:02:11Z"
}

Resumable upload

Create a session, then send chunks with Content-Range. Chunks can be any size from 5 MB up; we use 32 MB in the CLI. If a chunk fails, resend it. If you lose the session ID, GET /v1/uploads lists sessions open on your token for the last 48 hours.

# 1. open a session
curl -X POST https://api.media-host.online/v1/uploads \
  -H "Authorization: Bearer $MH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"collection":"lectures","filename":"week-07.mp4","bytes":2147483648}'

# → { "upload_id": "up_K3m9...", "chunk_size_hint": 33554432 }

# 2. send chunks (repeat; order does not matter)
curl -X PUT https://api.media-host.online/v1/uploads/up_K3m9.../chunk \
  -H "Authorization: Bearer $MH_TOKEN" \
  -H "Content-Range: bytes 0-33554431/2147483648" \
  --data-binary @part-000

# 3. finish
curl -X POST https://api.media-host.online/v1/uploads/up_K3m9.../complete \
  -H "Authorization: Bearer $MH_TOKEN"

Or let the CLI handle it. It splits, retries and resumes on its own:

mh put lectures ./week-07.mp4 --title "Week 7: Signals and noise"

Metadata fields

fieldtypenotes
titlestringUsed in generated feeds. Defaults to filename without extension.
descriptionstringPlain text or limited HTML (p, a, b, i, br).
published_atRFC 3339Future dates keep the item out of the feed until then.
episode, seasonintegerMapped to iTunes tags.
privatebooleanServe only via signed URLs. Default follows the collection.

Processing states

processing → ready in normal cases. failed means we couldn't parse the container; the file is still stored and served, but duration is unknown and feeds will omit itunes:duration. Subscribe to the file.ready webhook rather than polling.

Accepted types: MP3, M4A/AAC, FLAC, WAV, OGG/Opus, MP4 (H.264/H.265), WebM, MOV. Anything else is stored as application/octet-stream and served with a download disposition.