Video management
Import video from M3U8 URL

Import video from M3U8 URL

If your videos are already packaged as HLS, you can bring them into AIOZ Stream without downloading and re-uploading the files. Send us the URL of an HLS master playlist (.m3u8) and our service copies every rendition and segment into your account. The copied video is then served through AIOZ Stream like any uploaded video.

Import is a byte-for-byte copy: nothing is re-encoded. The qualities you get are exactly the variants listed in your source manifest.

When to use import

  • Migrating a library: Move existing HLS content from another platform or CDN into AIOZ Stream.
  • No local file: The video only exists as an HLS stream and you do not have the original MP4 or MOV file.
  • Keep your encoding: You already encoded the video with the bitrates and codecs you want and do not want them changed.

If you have the original file, or you want AIOZ Stream to choose or customize the output qualities, upload the file instead.

How it works

  1. You call POST /api/media/create with a source_url pointing to an HLS master playlist.
  2. Our service fetches the master playlist and checks it. If it is not a valid master playlist, the request fails immediately with 400 Bad Request.
  3. If the check passes, the video object is created and the API answers 202 Accepted. The video status is transcoding.
  4. In the background, our service downloads every variant playlist and segment and stores them in your account. If a step fails, the import is retried, up to 3 attempts in total.
  5. When the copy finishes, the video status becomes done and it is ready to play. If every attempt fails, the status becomes fail.

Source requirements

The source_url must meet all of the following:

  • Master playlist: The URL must point to an HLS master playlist, and every variant (#EXT-X-STREAM-INF) must declare a RESOLUTION. A media playlist (a single rendition listing segments directly) is rejected.
  • Finished VOD: Each variant playlist must end with #EXT-X-ENDLIST. Live and EVENT playlists are not supported.
  • Not encrypted: Playlists using #EXT-X-KEY with any method other than NONE (for example AES-128, SAMPLE-AES or DRM) are not supported.
  • No byte ranges: Playlists using #EXT-X-BYTERANGE are not supported.
  • At most one #EXT-X-MAP per variant playlist.
  • Segment formats: MPEG-TS (.ts) and fMP4 segments are supported.
  • Audio: Audio muxed into the video segments and separate audio renditions (#EXT-X-MEDIA:TYPE=AUDIO) are both supported. See Audio tracks for how separate audio must be laid out.
  • Video only: Every variant needs a RESOLUTION, so audio-only playlists cannot be imported. Subtitle renditions (TYPE=SUBTITLES) are ignored.
  • Publicly reachable: The manifest and segments must be downloadable with a plain HTTP GET over http or https, returning status 200. Custom headers, cookies and signed-request credentials cannot be passed. Hosts that resolve to private, loopback or link-local addresses are rejected, and at most 5 redirects are followed.

The URL does not need to end in .m3u8: any URL whose response is a valid HLS master playlist is accepted. The URL itself can be at most 2048 characters.

If your manifest uses signed URLs or tokens, make sure they stay valid long enough for the whole import to finish, including retries.

Audio tracks

HLS packages audio in two ways, and import supports both:

  • Muxed audio: The audio is inside the same segments as the video. It is copied as part of each video rendition.
  • Separate audio renditions: The audio has its own playlists, declared with #EXT-X-MEDIA:TYPE=AUDIO and referenced by each variant through AUDIO="<group-id>". The audio segments are copied byte for byte, like the video, and the audio codec declared in the variant's CODECS is kept.

How separate audio is imported depends on how many variants use each group:

Source layoutResult
A group referenced by two or more variantsEvery rendition in the group (for example, one per language) is imported and shared by all qualities.
A group referenced by exactly one variantThe group must hold exactly one rendition. It is attached to that variant's quality.
A group that no variant referencesSkipped.

For separate audio, the manifest must also follow these rules:

  • Either every variant references an audio group, or none does.
  • Every group a variant references must be declared with #EXT-X-MEDIA.
  • Each audio rendition must meet the same requirements as a video one: a finished VOD playlist, not encrypted, no byte ranges.
  • Audio renditions count toward the renditions-per-video limit below.

Here is an example of a supported master playlist, with two qualities sharing English and Spanish audio:

#EXTM3U
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud",NAME="English",LANGUAGE="en",DEFAULT=YES,URI="audio/en.m3u8"
#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID="aud",NAME="Español",LANGUAGE="es",URI="audio/es.m3u8"
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720,CODECS="avc1.64001f,mp4a.40.2",AUDIO="aud"
video/720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080,CODECS="avc1.640028,mp4a.40.2",AUDIO="aud"
video/1080p.m3u8

Limits

LimitValue
Master and variant playlist size2 MiB
Size of a single segment200 MiB
Segments per rendition5000
Renditions per video (video + audio)10
Duration per rendition4 hours
Timeout per HTTP request to your origin30 seconds

Importing a video

Step 1: Get your credentials

Import uses the same authentication as other media endpoints: either a Bearer access token, or an API key pair sent as the stream-public-key and stream-secret-key headers. Both Full Access and Upload-Only API keys can start an import.

Step 2: Send the import request

Call POST /api/media/create with a title and the source_url of your master playlist.

Example: Importing a video using curl

curl --location 'https://api.aiozstream.network/api/media/create' \
--header 'stream-public-key: your_public_key_here' \
--header 'stream-secret-key: your_secret_key_here' \
--header 'Content-Type: application/json' \
--data '{
    "title": "My imported video",
    "source_url": "https://cdn.example.com/videos/my-video/master.m3u8"
}'

You can also set the usual video fields:

{
  "title": "My imported video",
  "description": "Migrated from our old CDN",
  "type": "video",
  "is_public": true,
  "tags": ["migration"],
  "metadata": [{ "key": "origin", "value": "old-cdn" }],
  "source_url": "https://cdn.example.com/videos/my-video/master.m3u8"
}
⚠️

Do not send qualities or watermark with an import. The qualities come from the source manifest and nothing is re-encoded, so a watermark cannot be applied. Requests that include either field are rejected with 400 Bad Request.

A successful request returns 202 Accepted with the new video object. Save the id: you need it to track the import.

{
  "status": "success",
  "data": {
    "id": "video_id",
    "type": "video",
    "title": "My imported video",
    "status": "transcoding",
    "qualities": null,
    "...": "..."
  }
}

Step 3: Track the import

The import runs in the background. You can follow it in two ways.

Poll the video status. Call the Get video detail endpoint until status is done or fail:

curl --location 'https://api.aiozstream.network/api/media/{video_id}' \
--header 'stream-public-key: your_public_key_here' \
--header 'stream-secret-key: your_secret_key_here'
StatusMeaning
transcodingThe import is queued or in progress.
doneAll renditions were copied. The video is ready to play.
failThe import failed after all retry attempts.

Use webhooks. Subscribe to webhooks to be notified instead of polling. Imports emit these events:

  • encoding.started: The import started. It is sent again at the start of each retry attempt, so your handler may receive it more than once.
  • encoding.finished: The import completed and the video is ready.
  • encoding.failed: The import failed after all retry attempts.

Imports do not emit file.received or partial.finished, and the qualities field of import webhook payloads is empty.

While a video is being imported it cannot be deleted. Wait until its status is done or fail.

Billing

Imported videos are billed for storage only. Because nothing is re-encoded, there is no transcoding cost.

Troubleshooting

Request rejected with 400 Bad Request

These errors are returned immediately, and no video is created.

Message containsCause and fix
Importing media from a URL is not enabled.Import is not available for this environment. Contact support.
Qualities cannot be set for an imported mediaRemove qualities from the request body.
Watermark cannot be applied to an imported media.Remove watermark from the request body.
Source url length must be less than 2048 characters.Shorten the URL.
source url must use http or httpsUse an http:// or https:// URL.
source url resolves to a non-public addressHost the manifest on a publicly reachable server.
master playlist variant is missing RESOLUTIONSend a master playlist, not a media playlist, and add RESOLUTION to every variant.
source playlist is not a finished VODThe URL is a live or unfinished media playlist. Import a finished master playlist instead.
could not parse the source as an HLS playlistThe URL did not return an HLS playlist. Check the URL and that it returns status 200.
every video rendition must reference the same kind of audio groupMake every variant reference an audio group, or none of them, and declare every group a variant references.
an audio group used by a single video rendition must hold exactly one renditionKeep one rendition in audio groups that only one variant uses.
source manifest exceeds a configured limitReduce the number of renditions or the manifest size. See Limits.
too many redirectsPoint source_url closer to the final location (at most 5 redirects).

Video status becomes fail

The master playlist passed the first check, but copying the variants or segments failed three times. Common causes:

  • A variant is a live or unfinished playlist (no #EXT-X-ENDLIST).
  • A variant is encrypted (#EXT-X-KEY) or uses #EXT-X-BYTERANGE.
  • A variant exceeds the segment, duration or segment-size limits.
  • The origin returned an error (for example 403 or 404) or timed out, for example because a signed URL expired.

Check your source against the requirements, then start a new import.

FAQs

Q: Which qualities will my imported video have?
A: Exactly the variants in your master playlist, with their original resolution, bitrate and codecs. You cannot add or change qualities during import.

Q: Can I import a live stream?
A: No. Only finished VOD playlists (with #EXT-X-ENDLIST) can be imported.

Q: Can I import a single media playlist?
A: No. Wrap it in a master playlist with one #EXT-X-STREAM-INF entry that declares RESOLUTION.

Q: Can I import DRM-protected or AES-encrypted content?
A: No. Encrypted playlists are rejected.

Q: Can I import an audio-only playlist?
A: Not yet. Every variant of the master playlist must declare a RESOLUTION, which audio-only playlists do not have.

Q: Can I import a video with several audio languages?
A: Yes, as separate audio renditions in one group that at least two variants reference. Every language in the group is imported. A master playlist with a single variant can only carry one audio rendition in its group. See Audio tracks.

Q: Are captions and subtitles imported?
A: No. Subtitle renditions (#EXT-X-MEDIA:TYPE=SUBTITLES) are ignored. Add captions to the video after the import finishes.

Next steps

See the Import video from HLS URL API reference for the full request and response schema, with examples in cURL, Node.js, Python and Go.