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
- You call
POST /api/media/createwith asource_urlpointing to an HLS master playlist. - 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. - If the check passes, the video object is created and the API answers
202 Accepted. The video status istranscoding. - 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.
- When the copy finishes, the video status becomes
doneand it is ready to play. If every attempt fails, the status becomesfail.
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 aRESOLUTION. A media playlist (a single rendition listing segments directly) is rejected. - Finished VOD: Each variant playlist must end with
#EXT-X-ENDLIST. Live andEVENTplaylists are not supported. - Not encrypted: Playlists using
#EXT-X-KEYwith any method other thanNONE(for example AES-128, SAMPLE-AES or DRM) are not supported. - No byte ranges: Playlists using
#EXT-X-BYTERANGEare not supported. - At most one
#EXT-X-MAPper 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
GEToverhttporhttps, returning status200. 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=AUDIOand referenced by each variant throughAUDIO="<group-id>". The audio segments are copied byte for byte, like the video, and the audio codec declared in the variant'sCODECSis kept.
How separate audio is imported depends on how many variants use each group:
| Source layout | Result |
|---|---|
| A group referenced by two or more variants | Every rendition in the group (for example, one per language) is imported and shared by all qualities. |
| A group referenced by exactly one variant | The group must hold exactly one rendition. It is attached to that variant's quality. |
| A group that no variant references | Skipped. |
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.m3u8Limits
| Limit | Value |
|---|---|
| Master and variant playlist size | 2 MiB |
| Size of a single segment | 200 MiB |
| Segments per rendition | 5000 |
| Renditions per video (video + audio) | 10 |
| Duration per rendition | 4 hours |
| Timeout per HTTP request to your origin | 30 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'| Status | Meaning |
|---|---|
transcoding | The import is queued or in progress. |
done | All renditions were copied. The video is ready to play. |
fail | The 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 contains | Cause 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 media | Remove 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 https | Use an http:// or https:// URL. |
source url resolves to a non-public address | Host the manifest on a publicly reachable server. |
master playlist variant is missing RESOLUTION | Send a master playlist, not a media playlist, and add RESOLUTION to every variant. |
source playlist is not a finished VOD | The URL is a live or unfinished media playlist. Import a finished master playlist instead. |
could not parse the source as an HLS playlist | The 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 group | Make 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 rendition | Keep one rendition in audio groups that only one variant uses. |
source manifest exceeds a configured limit | Reduce the number of renditions or the manifest size. See Limits. |
too many redirects | Point 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
403or404) 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.