Search
Close this search box.

How To Get Direct URL Link to bunny.net videos

Direct download url from bunny.net
Play Video about Direct download url from bunny.net

Table of Contents

1. Introduction

Struggling with direct URL links to bunny.net videos? Cannot get back content you uploaded?

This is are common people problems but only few knows how to solve them. In this knowledge article I want to explain you different ways to get direct URL to your video content as well as I will show you how to download whole catalog.

2. Download content without API

If you don’t want to play with Postman, scripting and API calls then you can read this and get benefit of UI.

Go to Stream section, select your video library then select your video and use triple dots menu to download it as zip.

UI menu to access stream section
Download button in UI graphic interface.

Zip archive has a name data.zip and present structure like below example, where you have mp4 files and catalogs with different resolutions of ts MPEG format. Note down presence of original file which is dependent from Encoding settings ‘Keep Original Files’ of your Stream section

				
					drwxr-xr-x@ 240p
drwxr-xr-x@ 360p
drwxr-xr-x@ 480p
drwxr-xr-x@ 720p
-rw-r--r--@ master.m3u8
-rw-r--r--@ original
-rw-r--r--@ play_240p.mp4
-rw-r--r--@ play_360p.mp4
-rw-r--r--@ play_480p.mp4
-rw-r--r--@ play_720p.mp4
-rw-r--r--@ playlist.m3u8
-rw-r--r--@ preview.gif
-rw-r--r--@ preview.webp
-rw-r--r--@ response.mp4
drwxr-xr-x@ seek
-rw-r--r--@ thumbnail.jpg
-rw-r--r--@ thumbnail_1.jpg
-rw-r--r--@ thumbnail_2.jpg
-rw-r--r--@ thumbnail_3.jpg
-rw-r--r--@ thumbnail_4.jpg
-rw-r--r--@ thumbnail_5.jpg
				
			

This way you can download your data without any coding or API calls.

3. Understanding API

There are 3 API endpoints with bunny:

List of API for bunny.net

In this article I will focus on Edge and main API because those will let you access video content.

3.1. Bunny.net API Postman authorization setup

As I mentioned you will get API key from your account settings under section API. Then you can setup it in Postman like below or save it to use in curl commands.

setup main API key for Postman for bunny net

3.2. Creating Example Video Library

To create example video library run:

				
					curl --location 'https://api.bunny.net/videolibrary' \
--header 'Content-Type: application/json' \
--header 'AccessKey: ********' \
--data '{
    "name":"exampleVideoLibrary"
}'
				
			

you should get response similar to below

				
					{
    "Id": 228555,
    "Name": "exampleVideoLibrary",
    "VideoCount": 0,
    "TrafficUsage": 0,
    "StorageUsage": 0,
    "DateCreated": "2024-04-07T19:24:53.8785176Z",
    "ReplicationRegions": [
        ""
    ],
    "ApiKey": "84e5d0d0-ba6a-4cda-9b816283abef-43b1-4a17",
    "ReadOnlyApiKey": "70da7626-d289-414b-9100d79e6f4b-ee4d-47bc",
    "HasWatermark": false,
    "WatermarkPositionLeft": 0,
    "WatermarkPositionTop": 0,
    "WatermarkWidth": 0,
    "PullZoneId": 2130446,
    "StorageZoneId": 634717,
    "WatermarkHeight": 0,
    "EnabledResolutions": "240p,360p,480p,720p,1080p",
    "ViAiPublisherId": null,
    "VastTagUrl": null,
    "WebhookUrl": null,
    "CaptionsFontSize": 20,
    "CaptionsFontColor": "#fff",
    "CaptionsBackground": "#000",
    "UILanguage": "en",
    "AllowEarlyPlay": false,
    "PlayerTokenAuthenticationEnabled": false,
    "AllowedReferrers": [],
    "BlockedReferrers": [],
    "BlockNoneReferrer": true,
    "EnableMP4Fallback": true,
    "KeepOriginalFiles": true,
    "AllowDirectPlay": true,
    "EnableDRM": false,
    "DrmVersion": 0,
    "AppleFairPlayDrm": {
        "Enabled": false,
        "CertificateId": null,
        "CertificateExpirationDate": null,
        "Provider": null
    },
    "GoogleWidevineDrm": {
        "Enabled": false,
        "CertificateId": null,
        "CertificateExpirationDate": null,
        "Provider": null,
        "SdOnlyForL3": false,
        "MinClientSecurityLevel": null
    },
    "Bitrate240p": 600,
    "Bitrate360p": 800,
    "Bitrate480p": 1400,
    "Bitrate720p": 2800,
    "Bitrate1080p": 5000,
    "Bitrate1440p": 8000,
    "Bitrate2160p": 25000,
    "ApiAccessKey": null,
    "ShowHeatmap": false,
    "EnableContentTagging": true,
    "PullZoneType": 1,
    "CustomHTML": null,
    "Controls": "play-large,play,progress,current-time,mute,volume,captions,settings,airplay,pip,fullscreen",
    "PlayerKeyColor": "#ff7755",
    "FontFamily": "Rubik",
    "WatermarkVersion": 0,
    "EnableTranscribing": false,
    "EnableTranscribingTitleGeneration": false,
    "EnableTranscribingDescriptionGeneration": false,
    "TranscribingCaptionLanguages": [],
    "RememberPlayerPosition": false
}
				
			

Returned StorageZoneId will let you localize where uploaded videos end up and ApiKey is to access Stream API. You can reset API key if you need but I haven’t found call to reset ReadOnlyApiKey.

				
					curl --request POST \
     --url https://api.bunny.net/videolibrary/634717/resetApiKey \
     --header 'AccessKey: *******'
				
			

3.3. Accessing linked to Library Storage

Because you have storage Zone ID you can ask for storage Zone individual password

				
					curl --location 'https://api.bunny.net/storagezone/634717' \
--header 'AccessKey: ******'
				
			

In return you will have details

				
					{
    "Id": 634717,
    "UserId": "1210c3d5-6a6e-4136-a135-91a4248be30b",
    "Name": "vz-084ff1d7-d63",
    "Password": "0ef54d0d-bb8b-4c01-96005e858992-6752-47b0",
    "DateModified": "2024-04-07T19:24:53",
    "Deleted": false,
    "StorageUsed": 0,
    "FilesStored": 0,
    "Region": "DE",
    "ReplicationRegions": [],
    "PullZones": [
        {
            "Id": 2130446,
            "Name": "vz-084ff1d7-d63",
            "OriginUrl": "",
            "Enabled": true,
            "Suspended": false,
            "Hostnames": [
                {
                    "Id": 3551293,
                    "Value": "vz-084ff1d7-d63.b-cdn.net",
                    "ForceSSL": false,
                    "IsSystemHostname": true,
                    "HasCertificate": true,
                    "Certificate": null,
                    "CertificateKey": null
                }
            ],
            "StorageZoneId": 634717,
...
}
				
			

Note down
“Name”: “vz-084ff1d7-d63”,
“Password”: “0ef54d0d-bb8b-4c01-96005e858992-6752-47b0”

because this you will need to list content of storage and to download particular file.

				
					curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0'
				
			

response:

				
					[]
				
			

Now video library and linked storage are empty so it give you empty array. Time to upload some videos.

3.4. Uploading example videos

 

3.4.1. Uploading directly to hidden Storage

For that you can use storage API to upload directly to hidden storage although it is not right approach because that storage was created for Video Library purpose and it’s not visible in bunny web page dashboard, neither video you will upload will be visible in video library list. Storage is to back up Video Library content.

				
					curl --location --request PUT 'https://storage.bunnycdn.com/vz-084ff1d7-d63/play_240p.mp4' \
--header 'Content-Type: video/mp4' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0' \
--data '@/videos/exampleVideo.mp4'
				
			

response

				
					{
    "HttpCode": 201,
    "Message": "File uploaded."
}
				
			

If you check storage again

				
					curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0'
				
			

you will see the file

				
					[
    {
        "Guid": "b8cfe836-5a5b-4c50-bec4-591591af8244",
        "StorageZoneName": "vz-084ff1d7-d63",
        "Path": "/vz-084ff1d7-d63/",
        "ObjectName": "play_240p.mp4",
        "Length": 2598574,
        "LastChanged": "2024-04-07T20:00:22.601",
        "ServerId": 613,
        "ArrayNumber": 0,
        "IsDirectory": false,
        "UserId": "1210c3d5-6a6e-4136-a135-91a4248be30b",
        "ContentType": "",
        "DateCreated": "2024-04-07T20:00:22.601",
        "StorageZoneId": 634717,
        "Checksum": "977FD2439E73CB30EA452C833DC3293B46A0B6AD8AC565360E8EB6E02EC26FFC",
        "ReplicatedZones": ""
    }
]
				
			

but you will not see it in the webpage UI that’s because metadata for video was not created

empty video library in bunny.net

3.4.2. Uploading via Stream API

When you created video library you got

“ApiKey”: “84e5d0d0-ba6a-4cda-9b816283abef-43b1-4a17”

in return and that you have to use to access Stream API. First step is to create video metadata and secondly upload binary file.

				
					curl --location 'https://video.bunnycdn.com/library/228555/videos' \
--header 'Content-Type: application/json' \
--header 'AccessKey: 84e5d0d0-ba6a-4cda-9b816283abef-43b1-4a17' \
--data '{
  "title": "SomeTitle"
}'
				
			

Note down guid (video ID) from response as you need it to upload binary file referencing that id.

				
					{
    "videoLibraryId": 228555,
    "guid": "5e778351-78d5-493d-b764-86b78ad566ff",
    "title": "SomeTitle",
    "dateUploaded": "2024-04-07T20:13:19.3811667Z",
    "views": 0,
...
    "transcodingMessages": []
}
				
			

Run below command to upload example video to created Library and video metadata

				
					curl --location --request PUT 'https://video.bunnycdn.com/library/228555/videos/5e778351-78d5-493d-b764-86b78ad566ff' \
--header 'Content-Type: video/mp4' \
--header 'AccessKey: 84e5d0d0-ba6a-4cda-9b816283abef-43b1-4a17' \
--data '@/videos/descript.mp4'
				
			

response telling you it was successfull

				
					{
    "success": true,
    "message": "OK",
    "statusCode": 200
}
				
			

Checking storage again will tell you that new catalog was created for video

				
					curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0'
				
			
				
					[
    {
        "Guid": "245c357e-7f08-42d6-ac90-9ea66b7c4c61",
        "StorageZoneName": "vz-084ff1d7-d63",
        "Path": "/vz-084ff1d7-d63/",
        "ObjectName": "5e778351-78d5-493d-b764-86b78ad566ff",
        "Length": 0,
        "LastChanged": "2024-04-07T21:12:58.398",
        "ServerId": 0,
        "ArrayNumber": 0,
        "IsDirectory": true,
        "UserId": "1210c3d5-6a6e-4136-a135-91a4248be30b",
        "ContentType": "",
        "DateCreated": "2024-04-07T21:12:58.398",
        "StorageZoneId": 634717,
        "Checksum": null,
        "ReplicatedZones": null
    },
    {
        "Guid": "b8cfe836-5a5b-4c50-bec4-591591af8244",
        "StorageZoneName": "vz-084ff1d7-d63",
        "Path": "/vz-084ff1d7-d63/",
        "ObjectName": "play_240p.mp4",
        "Length": 2598574,
        "LastChanged": "2024-04-07T20:00:22.601",
        "ServerId": 613,
        "ArrayNumber": 0,
        "IsDirectory": false,
        "UserId": "1210c3d5-6a6e-4136-a135-91a4248be30b",
        "ContentType": "",
        "DateCreated": "2024-04-07T20:00:22.601",
        "StorageZoneId": 634717,
        "Checksum": "977FD2439E73CB30EA452C833DC3293B46A0B6AD8AC565360E8EB6E02EC26FFC",
        "ReplicatedZones": ""
    }
]
				
			

If you visit right now bunny net web page you will noticed new video in video library

new video in video library

3.5. Downloading particular videos

If you decide to download it via button ‘Download’ then you will get data.zip which is compressed content of catalog that you can get with following API call

				
					curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/5e778351-78d5-493d-b764-86b78ad566ff/' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0'
				
			

So if you want to download file instead listing catalog content you need to point to file, the object that has IsDirectory property set as false. For example

				
					    {
        "Guid": "5485ec58-1780-4dca-a80a-d144b71fe699",
        "StorageZoneName": "vz-084ff1d7-d63",
        "Path": "/vz-084ff1d7-d63/5e778351-78d5-493d-b764-86b78ad566ff/",
        "ObjectName": "play_360p.mp4",
        "Length": 1729453,
        "LastChanged": "2024-04-07T21:13:16.141",
        "ServerId": 632,
        "ArrayNumber": 0,
        "IsDirectory": false,
        "UserId": "1210c3d5-6a6e-4136-a135-91a4248be30b",
        "ContentType": "",
        "DateCreated": "2024-04-07T21:13:16.141",
        "StorageZoneId": 634717,
        "Checksum": "C323EE4CACB1D0E72A1EEAED1A7DFA694FC8B090C0106DDAA3906188F7FDD11E",
        "ReplicatedZones": ""
    }
				
			

Then to download run command

				
					curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/5e778351-78d5-493d-b764-86b78ad566ff/play_360p.mp4' \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0' \
-o play_360p.mp4

# or including key in parameter
curl --location 'https://storage.bunnycdn.com/vz-084ff1d7-d63/5e778351-78d5-493d-b764-86b78ad566ff/play_360p.mp4?accessKey=0ef54d0d-bb8b-4c01-96005e858992-6752-47b0&download' \
-o play_360p.mp4
				
			

3.6. Downloading catalog with all video files

For that basically run curl that pointing to catalog with parameter download.

				
					curl --location https://storage.bunnycdn.com/vz-084ff1d7-d63/5e778351-78d5-493d-b764-86b78ad566ff/?download \
--header 'AccessKey: 0ef54d0d-bb8b-4c01-96005e858992-6752-47b0' \
-o 5e778351-78d5-493d-b764-86b78ad566ff.zip
				
			

3.7. Getting link to share via player

Link that will work with player on the webpage can be taken via Pull Zone.

If you are operating on bunny.net UI you cannot create pull zone for storage linked with Video Library for the Stream but because we are in API section such things are absolutely possible.

Therefore you can run

				
					curl --location 'https://api.bunny.net/pullzone' \
--header 'Content-Type: application/json' \
--header 'AccessKey: *********' \
--data '{
    "Name": "PullZoneForHiddenStorage",
    "OriginType": 2,
    "StorageZoneId": 634717
}'
				
			

Origin type 2 is for storage zone and storage zone id pointing to same storage that backing your video library files.

Response:

				
					{
    "Id": 2132300,
    "Name": "PullZoneForHiddenStorage",
    "OriginUrl": "",
    "Enabled": true,
    "Suspended": false,
    "Hostnames": [
        {
            "Id": 3554220,
            "Value": "PullZoneForHiddenStorage.b-cdn.net",
            "ForceSSL": false,
            "IsSystemHostname": true,
            "HasCertificate": true,
            "Certificate": null,
            "CertificateKey": null
        }
    ],
    "StorageZoneId": 634717,
    "EdgeScriptId": -1,
    "EdgeScriptExecutionPhase": 0,
    "MagicContainersAppId": null,
    "AllowedReferrers": [],
    "BlockedReferrers": [],
    "BlockedIps": [],
...
    "ZoneSecurityEnabled": false,
    "ZoneSecurityKey": "9d7e4457-7b94-4e94-b11b-8774b8b4de95",
    "CnameDomain": "b-cdn.net",
...
    "VideoLibraryId": -1,
...
    "OriginType": 2,
    "OriginLinkValue": "vz-084ff1d7-d63",


}
				
			

Now you can get access to the file with pull zone new hostname

				
					curl --location 'https://pullzoneforhiddenstorage.b-cdn.net/play_240p.mp4'
				
			

or files created by transcoding uploaded content to Video Library

				
					curl --location 'https://pullzoneforhiddenstorage.b-cdn.net/5e778351-78d5-493d-b764-86b78ad566ff/play_360p.mp4'
				
			

URLs exposed via pull zone can be used as source for Presto Player to include in your web page.

This does not work with URLs to storage.

ZoneSecurityKey is ‘Url Token Authentication Key’ that you can see in UI.

3.7.1. Enable token authentication

I couldn’t find API call that will enable token authentication. Updating Pull Zone property ZoneSecurityEnabled as true does not work. But I found workaround.

First you create Edge Rule that will enable that, then you can remove that edge rule to keep things clean. Tested & works although looks silly.

				
					curl --location 'https://api.bunny.net/pullzone/2132312/edgerules/addOrUpdate' \
--header 'Content-Type: application/json' \
--header 'AccessKey: ******' \
--data '{
  "ActionType": 9,
  "TriggerMatchingType": 0,
  "Enabled": true,
  "Triggers": [
    {
      "Type": 9,
      "PatternMatchingType": 1,
      "PatternMatches": [
        "GET"
      ]
    }
  ]
}'
				
			

As response you getting guid that you will use to delete that rule

				
					{
    "Guid": "6596594f-ee3c-4a8a-b7ad-b9ebcdcd074d",
    "ActionType": 9,
    "ActionParameter1": "",
    "ActionParameter2": "",
    "Triggers": [
        {
            "Type": 9,
            "PatternMatches": [
                "GET"
            ],
            "PatternMatchingType": 1,
            "Parameter1": null
        }
    ],
    "ExtraActions": [],
    "TriggerMatchingType": 0,
    "Description": null,
    "Enabled": true
}
				
			

Now deleting:

				
					curl --location --request DELETE 'https://api.bunny.net/pullzone/2132312/edgerules/6596594f-ee3c-4a8a-b7ad-b9ebcdcd074d' \
--header 'AccessKey: *****'
				
			

3.7.2. Sign request URL

Once authentication is enabled you cannot access same video without token. To generate token you can use simple shell commands

				
					security_key="8e543f2a-a21d-4df9-96b6-3e97debf8860"
expiration_time=3600
expires=$(($(date +%s) + expiration_time))
signature_path="/play_240p.mp4"

hashable_base=$security_key$signature_path$expires
token=$(echo -n $hashable_base | shasum -a 256 | xxd -r -p | base64)

token=$(echo $token | tr -d '\n' | tr '+' '-' | tr '/' '_' | tr -d '=')

echo "https://pullzoneforhiddenstorage.b-cdn.net$signature_path?token=$token&expires=$expires"
				
			

This URL you can put as well as source for Presto Player and display on your website.

4. Conclusion

Important point to mention is all examples are rather educational than real implementation. All API request should be handled as backend code on webserver side. This include signing URLs of course. Therefore I am happy you will get this as initial starting point and enjoy that knowledge in your projects.

Have a nice coding!

get Presto Player simple

Leave a Reply

Your email address will not be published. Required fields are marked *

Follow me on LinkedIn
Share the Post:

Enjoy Free Useful Amazing Content

Related Posts