PHPackages                             bluebillywig/bb-sapi-php-sdk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. bluebillywig/bb-sapi-php-sdk

ActiveLibrary[API Development](/categories/api)

bluebillywig/bb-sapi-php-sdk
============================

v2.0.0(1mo ago)01.9k↓36.1%[1 PRs](https://github.com/bluebillywig/bb-sapi-php-sdk/pulls)MITPHPCI passing

Since Nov 4Pushed 1mo ago7 watchersCompare

[ Source](https://github.com/bluebillywig/bb-sapi-php-sdk)[ Packagist](https://packagist.org/packages/bluebillywig/bb-sapi-php-sdk)[ RSS](/packages/bluebillywig-bb-sapi-php-sdk/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (4)Dependencies (22)Versions (24)Used By (0)

Blue Billywig SAPI PHP SDK
==========================

[](#blue-billywig-sapi-php-sdk)

This PHP SDK provides abstractions to interact with the Blue Billywig Server API.

Requirements
------------

[](#requirements)

- PHP &gt;= 8.1

Installation
------------

[](#installation)

```
composer require bluebillywig/bb-sapi-php-sdk
```

Quick Start
-----------

[](#quick-start)

```
use BlueBillywig\Sdk;

$sdk = Sdk::withRPCTokenAuthentication(
    'my-publication',
    1,                // token ID
    'shared-secret'   // shared secret
);

// List media clips
$response = $sdk->mediaclip->list();
$data = $response->getDecodedBody();
print_r($data);
```

Authentication
--------------

[](#authentication)

The SDK uses HOTP-based RPC token authentication. You need a **token ID** and **shared secret** from your Blue Billywig publication settings.

```
use BlueBillywig\Sdk;
use BlueBillywig\Authentication\RPCTokenAuthenticator;

// Recommended: use the convenience factory
$sdk = Sdk::withRPCTokenAuthentication('my-publication', $tokenId, $sharedSecret);

// Or provide a custom authenticator
$authenticator = new RPCTokenAuthenticator($tokenId, $sharedSecret);
$sdk = new Sdk('my-publication', $authenticator);
```

**Clock synchronization**: The RPC token is time-based (HOTP). Both client and server clocks must be reasonably synchronized (within the token expiration window, default 120 seconds). Significant clock drift will cause authentication failures.

Entities
--------

[](#entities)

All entities support standard CRUD operations where applicable:

EntityListGetCreateUpdateDelete`$sdk->mediaclip`YesYesYesYesYes`$sdk->playlist`YesYesYesYesYes`$sdk->channel`YesYesYesYesYes`$sdk->playout`YesYesYesYesYes`$sdk->subtitle`YesYesYesYesYes`$sdk->thumbnail`-----### Sync and Async

[](#sync-and-async)

Every entity method is available in both synchronous and asynchronous variants. Async methods return a `GuzzleHttp\Promise\PromiseInterface`.

```
// Synchronous
$response = $sdk->mediaclip->list();

// Asynchronous
$promise = $sdk->mediaclip->listAsync();
$response = $promise->wait();
```

### Media Clips

[](#media-clips)

```
// List
$response = $sdk->mediaclip->list(15, 0, 'createddate desc');

// Get (with optional language and job inclusion)
$response = $sdk->mediaclip->get(123);
$response = $sdk->mediaclip->get(123, 'en', false);

// Create
$response = $sdk->mediaclip->create(['title' => 'My Video']);

// Update
$response = $sdk->mediaclip->update(123, ['title' => 'Updated Title']);

// Delete (with optional purge)
$response = $sdk->mediaclip->delete(123);
$response = $sdk->mediaclip->delete(123, true); // purge
```

### Playlists, Channels, Playouts, Subtitles

[](#playlists-channels-playouts-subtitles)

```
// All follow the same pattern
$response = $sdk->playlist->list();
$response = $sdk->playlist->get(1);
$response = $sdk->playlist->create(['title' => 'My Playlist']);
$response = $sdk->playlist->update(1, ['title' => 'Updated']);
$response = $sdk->playlist->delete(1);
```

File Uploads
------------

[](#file-uploads)

The SDK supports single-chunk and multi-part uploads to S3 via presigned URLs.

```
// 1. Initialize the upload
$initResponse = $sdk->mediaclip->initializeUpload('/path/to/video.mp4');
$initResponse->assertIsOk();
$uploadData = $initResponse->getDecodedBody();

// 2. Execute the upload
$success = $sdk->mediaclip->helper->executeUpload('/path/to/video.mp4', $uploadData);

// 3. (Optional) Track upload progress
foreach ($sdk->mediaclip->helper->uploadProgressGenerator(
    $uploadData['listPartsUrl'],
    $uploadData['headObjectUrl'],
    $uploadData['chunks'],
) as $progress) {
    echo "Upload progress: {$progress}%\n";
}
```

Async upload using coroutines:

```
use GuzzleHttp\Promise\Coroutine;

$promise = Coroutine::of(function () use ($sdk, $mediaClipPath) {
    $response = (yield $sdk->mediaclip->initializeUploadAsync($mediaClipPath));
    $response->assertIsOk();

    yield $sdk->mediaclip->helper->executeUploadAsync($mediaClipPath, $response->getDecodedBody());
});
$promise->wait();
```

Thumbnails
----------

[](#thumbnails)

```
// Generate an absolute thumbnail URL with dimensions
$url = $sdk->thumbnail->helper->getAbsoluteImagePath('/path/to/image.jpg', 640, 360);
// => https://my-publication.bbvms.com/image/640/360/path/to/image.jpg
```

Response Handling
-----------------

[](#response-handling)

All entity methods return a `SapiResponse` object:

```
$response = $sdk->mediaclip->get(123);

// Check status
if ($response->isOk()) {
    $data = $response->getDecodedBody();
}

// Or assert (throws on non-2xx)
$response->assertIsOk();
$data = $response->getDecodedBody();

// Access response details
$response->getStatusCode();            // e.g. 200
$response->getBody()->getContents();   // raw body string
$response->getJsonBody();              // parse as JSON
$response->getXmlBody();               // parse as XML
$response->getDecodedBody();           // try JSON first, then XML
$response->getStatusCodeCategory();    // HTTPStatusCodeCategory enum
$response->getRequest();               // the original Request object

// Batch response utilities
Response::allOk($responses);           // true if all 2xx
Response::assertAllOk($responses);     // throws on first non-2xx
Response::getFailedResponses($responses); // generator yielding non-2xx responses
```

Error Handling
--------------

[](#error-handling)

The SDK throws typed exceptions for HTTP errors:

```
use BlueBillywig\Exception\HTTPRequestException;
use BlueBillywig\Exception\HTTPClientErrorRequestException;
use BlueBillywig\Exception\HTTPServerErrorRequestException;

try {
    $response = $sdk->mediaclip->get(999);
    $response->assertIsOk();
} catch (HTTPClientErrorRequestException $e) {
    // 4xx error
    echo "Client error {$e->getCode()}: {$e->getMessage()}\n";
    echo "Response body: {$e->getResponseBody()}\n";
} catch (HTTPServerErrorRequestException $e) {
    // 5xx error
    echo "Server error {$e->getCode()}: {$e->getMessage()}\n";
}
```

Configuration
-------------

[](#configuration)

```
$sdk = Sdk::withRPCTokenAuthentication('my-publication', $tokenId, $sharedSecret, [
    // Pass any Guzzle client options
    // See: https://docs.guzzlephp.org/en/stable/request-options.html
]);
```

Development
-----------

[](#development)

```
# Install dependencies
composer install

# Lint
composer run lint

# Run tests
composer run test:unit

# Run tests with coverage
composer run test:unit:coverage
```

###  Health Score

47

—

FairBetter than 94% of packages

Maintenance88

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 55% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~227 days

Recently: every ~270 days

Total

6

Last Release

59d ago

Major Versions

v1.0.4 → v2.0.02026-03-20

### Community

Maintainers

![](https://www.gravatar.com/avatar/e1f4b0048d61164561e20910cf69cd85d7aebec8e8e1c0aad3a354171d01ac37?d=identicon)[martijnbots](/maintainers/martijnbots)

---

Top Contributors

[![ghultink](https://avatars.githubusercontent.com/u/9196789?v=4)](https://github.com/ghultink "ghultink (11 commits)")[![martijnbots](https://avatars.githubusercontent.com/u/22675627?v=4)](https://github.com/martijnbots "martijnbots (7 commits)")[![jkoppen-bluebillywig](https://avatars.githubusercontent.com/u/12153885?v=4)](https://github.com/jkoppen-bluebillywig "jkoppen-bluebillywig (1 commits)")[![voyagen](https://avatars.githubusercontent.com/u/47989641?v=4)](https://github.com/voyagen "voyagen (1 commits)")

###  Code Quality

TestsCodeception

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/bluebillywig-bb-sapi-php-sdk/health.svg)

```
[![Health](https://phpackages.com/badges/bluebillywig-bb-sapi-php-sdk/health.svg)](https://phpackages.com/packages/bluebillywig-bb-sapi-php-sdk)
```

###  Alternatives

[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3731.2M42](/packages/tencentcloud-tencentcloud-sdk-php)[mvdnbrk/dhlparcel-php-api

DHL Parcel API client for PHP

3957.9k5](/packages/mvdnbrk-dhlparcel-php-api)[convertkit/convertkitapi

Kit PHP SDK for the Kit API

2167.1k1](/packages/convertkit-convertkitapi)[mapado/rest-client-sdk

Rest Client SDK for hydra API

1125.9k2](/packages/mapado-rest-client-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
