Download the PHP package gosuccess/bunny-api without Composer
On this page you can find all versions of the php package gosuccess/bunny-api. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download gosuccess/bunny-api
More information about gosuccess/bunny-api
Files in gosuccess/bunny-api
Package bunny-api
Short Description A modern, strongly-typed, dependency-free PHP client for all bunny.net APIs.
License MIT
Homepage https://github.com/GoSuccessHQ/bunny-api
Informations about the package bunny-api
bunny.net API – PHP Client
A modern, strongly-typed, dependency-free PHP client for the bunny.net APIs, built for PHP 8.4+.
Features
- Fully typed:
final readonlymodels, native enums and generics-annotated pagination for every endpoint, checked with PHPStan at the highest level. - Zero Composer dependencies: a self-contained cURL transport (only
ext-curlandext-jsonare required), pluggable through a small interface. - Partial updates done right: a field you leave out is not sent, a field you
set to
nullis cleared. - Lazy pagination across all pages with
all(), or page by page withlist(). - Safe retries: rate limits (
429) are retried honoringRetry-After; server and network errors only for idempotent requests, so an update is never applied twice. - Typed exceptions that normalize the error formats of all bunny.net APIs and
carry the
cdn-requestidfor support cases. - Generated from bunny.net's specifications, with the deviations between specification and reality corrected by hand, based on read-only checks against the live API and on bunny.net's own tools.
Supported APIs
| API | Namespace | Access |
|---|---|---|
| Core Platform API | GoSuccess\Bunny\Core |
$bunny->core |
| Origin Errors API | GoSuccess\Bunny\OriginErrors |
$bunny->originErrors |
| CDN Logging API | GoSuccess\Bunny\Logging |
$bunny->logging |
| Edge Storage API | GoSuccess\Bunny\Storage |
$bunny->storage(...) |
| Stream API | GoSuccess\Bunny\Stream |
$bunny->stream(...) |
| Shield API | GoSuccess\Bunny\Shield |
$bunny->shield |
| Edge Scripting API | GoSuccess\Bunny\EdgeScripting |
$bunny->edgeScripting |
| Magic Containers API | GoSuccess\Bunny\MagicContainers |
$bunny->magicContainers |
Requirements
- PHP 8.4 or higher
ext-curlandext-json
Installation
Quick start
Bunny creates each API client on first access and lets them share one HTTP
connection pool. Every client can also be used on its own:
The account API key is shown in the bunny.net dashboard under Account settings → API key.
Core Platform API
Pull zones, edge rules, DNS, storage zones, video libraries, statistics, billing, the audit log and more. See the API reference for every method.
Pull zones and hostnames
Edge rules
DNS
Statistics
Dates are always sent as UTC. Dates bunny.net returns without a time zone are read as UTC as well.
Origin Errors API
Requests the CDN could not complete because the origin failed: DNS failures, timeouts (the CDN waits 60 seconds), connection errors and the like.
The day is taken in UTC. bunny.net only retains recent days and does not
document how to fetch more errors when $log->hasMoreData is set.
CDN Logging API
Raw request logs of the last 3 days, filtered on the server:
status, cacheStatus and country take comma-separated lists; the time
range must lie within the retention window. bunny.net allows 30 requests per 10
seconds and pull zone.
The legacy v1 endpoint returns a whole day as a pipe-delimited file. The client streams it into a temporary file and parses the lines while you iterate, so even large logs use little memory:
Edge Storage API
Edge Storage authenticates with the storage zone's password, not the account API key, and every region has its own host:
Uploads send the file's SHA-256 checksum, so bunny.net rejects a corrupted
upload; pass verifyChecksum: false to skip the extra read. Deleting the root of
a zone requires deleteDirectory('/', allowRoot: true). Transfers are not
limited by the regular request timeout but by ClientOptions::$transferTimeout
(unlimited by default; a stalled transfer is aborted after 60 seconds).
describe(), exists(), createDirectory() and the contentType of an upload
use parts of the API that the specification does not document; they behave the
way bunny.net's own CLI uses them.
Stream API
Stream authenticates with the video library's own API key, not the account API key, and every path contains the library ID. The client takes both once:
A client with the read-only key (streamFor($library, readOnly: true)) can call
every reading method except videos->storageSize(), which bunny.net only answers
for the full key.
Uploads from the browser
Large files are best uploaded resumably with TUS, straight from the browser to bunny.net. Presign the upload on your server, so the API key never leaves it:
TUS clients that expect the raw Upload-Metadata header get it from
TusUpload::metadata('video/mp4', 'Product tour').
Resumable uploads from PHP
Large files and unstable connections are better served by TUS on the server, too. The uploader sends the file in chunks (16 MiB by default), each with a SHA-1 checksum; after a network failure or a server error it asks bunny.net how much arrived and continues from there:
To survive the end of the process as well, store the session before uploading and resume it later, from wherever the server stands:
An unfinished upload stays resumable until its signature expires (after one day
by default, see expires) or after about 48 hours without activity.
Embed token authentication
When a library requires signed embed URLs, sign them with the library's token authentication key (dashboard → Stream → library → Security):
Webhooks
Bunny Stream signs its webhook calls with the library's read-only API key.
WebhookSignature::parse() verifies the signature against the exact raw body in
constant time and returns the event:
Shield API
Shield protects pull zones with a WAF, rate limits, access lists, bot detection, upload scanning and API Guardian. Everything is organized by Shield zone:
The event logs of the last 72 hours can also be searched, grouped and exported as CSV:
A new custom access list starts disabled, with the action Log. configure()
makes it effective; it takes the configuration ID that list() reports for the
list, not the list ID:
Custom block, challenge and rate limit pages are plain HTML:
Shield answers many failures, "not found" among them, with 202 Accepted and
the error in the body. The client raises them like error statuses (see
Error handling), so a missing rule never comes back as an
empty object.
Edge Scripting API
Edge scripts run on bunny.net's edge. Create one, upload its code and publish it; variables and secrets reach the script as environment variables:
Secret values can be written but never read back; secrets->list() returns
their names only.
Magic Containers API
Magic Containers runs containerized applications on bunny.net's edge:
Applications are created and changed with request models such as
AddApplicationRequest and PatchApplicationRequest; lists are paged by cursor,
and all() follows the cursors for you.
Partial updates and clearing fields
Request models serialize only what you pass, so an update touches nothing
else. A field you leave out and a field you set to null therefore mean two
different things:
To make a field conditional, pass the Undefined sentinel, which is the default
of every optional field:
Pagination
List endpoints come in pairs: list() returns one Page, all() returns a lazy
Paginator over every item of every page.
Error handling
Every exception the library throws implements
GoSuccess\Bunny\Exception\BunnyException. Error responses become typed
exceptions:
| Status | Exception |
|---|---|
| 400 | BadRequestException |
| 401 | AuthenticationException |
| 403 | ForbiddenException |
| 404 | NotFoundException |
| 409 | ConflictException |
| 422 | ValidationException |
| 429 | RateLimitException (with $retryAfter) |
| 5xx | ServerException |
| other | ApiException |
All of them extend ApiException, which carries $statusCode, $errorKey (e.g.
pullZone.not_found), $field, $requestId (quote it when contacting bunny.net
support) and the raw $responseBody. Network failures throw a
TransportException, unexpected response bodies a SerializationException.
The Shield API reports many failures with 202 Accepted and the error in the
body. These are raised, too: as NotFoundException for error keys starting with
not_found, otherwise as ApiException (e.g. invalid_plan_type.bot_detection
for a feature the zone's plan lacks). Shield also answers some rejected requests
with 401, e.g. event logs of a day older than the kept three days
(invalid_datetime_window.event_logs); as the API key is not the problem, these
are raised as BadRequestException. $statusCode keeps the actual status.
Configuration
A 429 is retried after Retry-After unless retryOnRateLimit is off; then
it throws the RateLimitException right away, which suits callers that have
to answer within a deadline of their own. A server error or a lost connection
is only retried for GET, PUT and DELETE, because bunny.net applies most
changes via POST and repeating such a request could apply it twice. Both
are retried regardless of retryOnRateLimit.
Rate limiting
bunny.net answers excess requests with 429, which the client retries. To stay
below a limit proactively, pass a rate limiter, e.g. the built-in sliding
window, or your own implementation of RateLimiter (for example backed by
Redis to share it across processes):
Custom transport
Implement GoSuccess\Bunny\Http\HttpClient to route requests through your own
HTTP stack, e.g. Guzzle, without the library depending on it:
The built-in cURL transport keeps connections alive and, on PHP 8.5, shares DNS, connection and TLS session caches across requests of a PHP worker.
Documentation and examples
- docs/: a reference page for every method, with the endpoint, signature, parameters and an example.
- examples/: runnable scripts. They only read data, so they are safe to run against a production account.
Development
Most enums, models, resources and clients under src/<Api>/ are generated
from the committed snapshots of bunny.net's specifications in
resources/specs/; they start with a "This file is generated"
comment. Everything else is written by hand, e.g. the Handwritten/ traits of
the resources. Naming decisions and every correction of the specifications
live in tools/config/, each correction with the evidence it is
based on.
CI regenerates everything and fails if the committed files are out of date.
The read-only integration tests check the client against a real account. They only send requests without side effects: GETs and a few reads that use POST, such as availability checks and searches:
License
MIT
All versions of bunny-api with dependencies
ext-curl Version *
ext-json Version *