Bunnyx

CIHex.pmDocs

Elixir client for the bunny.net API. Built on Req.

Covers the full bunny.net platform — CDN, edge storage, S3-compatible storage, DNS, video streaming, Shield/WAF, edge scripting, magic containers, billing, and more.

Installation

def deps do
  [
    {:bunnyx, "~> 0.2.0"}
  ]
end

Quick start

Create a client and pass it to every call. No global config needed — multiple clients with different credentials work side by side.

client = Bunnyx.new(api_key: "sk-...")

# CDN — returns a %Bunnyx.PullZone{} struct
{:ok, zone} = Bunnyx.PullZone.create(client, name: "my-zone", origin_url: "https://example.com")
zone.id      #=> 12345
zone.name    #=> "my-zone"

# DNS
{:ok, dns} = Bunnyx.DnsZone.create(client, domain: "example.com")
{:ok, record} = Bunnyx.DnsRecord.add(client, dns.id, type: 0, name: "www", value: "1.2.3.4", ttl: 300)

# Typos fail fast
Bunnyx.PullZone.create(client, nme: "oops")
#=> ** (ArgumentError) unknown key :nme. Valid keys: :name, :origin_url, ...

Clients

bunny.net uses different authentication for different services. Bunnyx provides four client types:

Client Auth Use for
Bunnyx.new/1 Account API key CDN, DNS, storage zones, video libraries, Shield, billing, and everything else
Bunnyx.Storage.new/1 Storage zone password File upload, download, delete, list
Bunnyx.S3.new/1 Zone name + password (SigV4) S3-compatible storage with multipart uploads
Bunnyx.Stream.new/1 Library API key Video CRUD, upload, collections, captions
# Edge storage — upload and download files
storage = Bunnyx.Storage.new(storage_key: "pw-...", zone: "my-zone")
{:ok, nil} = Bunnyx.Storage.put(storage, "/images/logo.png", image_data)
{:ok, data} = Bunnyx.Storage.get(storage, "/images/logo.png")

# S3-compatible storage
s3 = Bunnyx.S3.new(zone: "my-zone", storage_key: "pw-...", region: "de")
{:ok, nil} = Bunnyx.S3.put(s3, "file.txt", "hello")
{:ok, result} = Bunnyx.S3.list(s3, prefix: "images/")

# Video streaming
stream = Bunnyx.Stream.new(api_key: "lib-key-...", library_id: 12345)
{:ok, video} = Bunnyx.Stream.create(stream, title: "My Video")
{:ok, nil} = Bunnyx.Stream.upload(stream, video.guid, video_binary)

API coverage

Main API (Bunnyx.new/1)

Separate clients

Error handling

All functions return {:ok, result} or {:error, %Bunnyx.Error{}}. Errors include the HTTP method and path for debugging:

case Bunnyx.PullZone.get(client, 999) do
  {:ok, zone} -> zone
  {:error, %Bunnyx.Error{status: 404}} -> nil
  {:error, error} -> raise "#{error.method} #{error.path}: #{error.message}"
end

Design

Bunnyx follows Elixir library conventions — no compile-time config, no global state, explicit clients.

Integration testing

The livebooks/ directory contains per-domain integration tests that exercise every SDK function against the real bunny.net API. Set LB_BUNNY_API_KEY and run the cells.

License

MIT — see LICENSE.