buble/sdk

Official PHP SDK for the Buble public API.

Maintainers

Package info

github.com/bublehq/php-sdk

Homepage

pkg:composer/buble/sdk

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.1 2026-05-26 09:22 UTC

This package is auto-updated.

Last update: 2026-05-26 09:32:52 UTC


README

Official PHP SDK for Buble, built for the Buble public API.

Use this SDK from server-side PHP applications to discover media models, upload source media, create asynchronous image and video generation tasks, run preconfigured Buble app workflows, and call chat models through OpenAI, Anthropic Messages, and Gemini-compatible API formats.

Keep API keys on the server. Do not expose BUBLE_API_KEY in browser, mobile, or other client-side code.

Installation

After publication to Packagist:

composer require buble/sdk

The package requires PHP 8.2+, ext-curl, and ext-json.

Quick Start

Set your API key:

export BUBLE_API_KEY="sk_..."

The generation examples below create real Buble generation tasks and may consume credits.

<?php

use Buble\BubleClient;
use Buble\Generations\CreateGenerationRequest;

$client = BubleClient::fromEnv();

$task = $client->generations()->create(
    CreateGenerationRequest::make(
        model: 'google/nano-banana',
        mode: 'text_to_image',
        prompt: 'A cinematic product photo of a matte black espresso cup',
    )->withParam('aspect_ratio', '1:1')
     ->withParam('output_format', 'png')
);

$result = $client->generations()->wait($task['data']['id']);
echo $result['data']['result']['images'][0]['url'] . PHP_EOL;

The client reads BUBLE_API_KEY and BUBLE_BASE_URL from the environment when omitted.

Configuration

use Buble\BubleClient;
use Buble\BubleClientOptions;

$client = new BubleClient(new BubleClientOptions(
    apiKey: 'sk_...',
    baseUrl: 'https://buble.ai',
    timeout: 60.0,
));

Discover Media Models

$models = $client->mediaModels()->list(mediaType: 'video');

foreach ($models['data'] as $model) {
    echo $model['model'] . PHP_EOL;
}

Use media model discovery as the source of truth for model keys, modes, required inputs, and public parameters. New Buble models can become available without an SDK release.

Upload Files

use Buble\Files\FileUpload;
use Buble\Files\UploadOptions;
use Buble\Generations\CreateGenerationRequest;

$uploaded = $client->files()->upload(
    FileUpload::fromPath('reference.png', 'image/png'),
    new UploadOptions(
        fileType: 'image',
        model: 'google/nano-banana',
        mode: 'image_to_image',
    ),
);

$task = $client->generations()->create(new CreateGenerationRequest(
    model: 'google/nano-banana',
    mode: 'image_to_image',
    prompt: 'Turn this reference into a polished ecommerce hero image.',
    imageUrls: [$uploaded['data']['url']],
));

Uploads support local paths, strings of bytes, and PHP stream resources. Path uploads are streamed from disk by cURL.

Video Generation

use Buble\WaitOptions;

$task = $client->generations()->create(
    CreateGenerationRequest::make(
        model: 'doubao/seedance-2.0-fast',
        mode: 'text_to_video',
        prompt: 'A slow cinematic shot of a futuristic train station at sunrise.',
    )->withParam('duration', '8s')
     ->withParam('resolution', '720p')
     ->withParam('aspect_ratio', '16:9')
);

$result = $client->generations()->wait(
    $task['data']['id'],
    new WaitOptions(interval: 2.0, timeout: 600.0),
);

Generation request bodies use Buble's flat public API shape. Put model-specific controls in withParam(...); the SDK serializes those controls at the JSON request root.

Do not send internal Buble fields such as input, options, scene, sub_mode_id, provider, mediaType, or media_type.

Apps

$app = $client->apps()->retrieve('video-background-remover');
print_r($app['data']['input_parameters']);

$task = $client->apps()->generations()->create('video-background-remover', [
    'source_video' => ['https://example.com/source.mp4'],
    'refine_foreground_edges' => true,
    'subject_is_person' => true,
]);

$result = $client->apps()->generations()->wait('video-background-remover', $task['data']['id']);

Apps are preconfigured workflows. Only send parameter names returned by apps()->list() or apps()->retrieve(...).

Chat

OpenAI-Compatible

$completion = $client->chat()->completions()->create([
    'model' => 'openai/gpt-5.5',
    'messages' => [
        ['role' => 'user', 'content' => 'Write a short launch summary.'],
    ],
    'max_completion_tokens' => 800,
]);

echo $completion['choices'][0]['message']['content'];

Streaming

foreach ($client->chat()->completions()->streamText([
    'model' => 'openai/gpt-5.5',
    'messages' => [
        ['role' => 'user', 'content' => 'Write one sentence at a time.'],
    ],
]) as $text) {
    echo $text;
}

Anthropic-Compatible

$message = $client->chat()->messages()->create([
    'model' => 'openai/gpt-5.5',
    'system' => 'You are concise.',
    'messages' => [
        ['role' => 'user', 'content' => 'Summarize this release.'],
    ],
    'max_tokens' => 800,
]);

Gemini-Compatible

$response = $client->chat()->gemini()->generateContent('openai/gpt-5.5', [
    'contents' => [
        [
            'role' => 'user',
            'parts' => [
                ['text' => 'Write a short launch summary.'],
            ],
        ],
    ],
]);

Gemini streaming uses streamGenerateContent, not stream: true on generateContent.

Chat methods preserve protocol-native response shapes as associative arrays.

Error Handling

use Buble\Exception\ApiException;
use Buble\Exception\GenerationFailedException;

try {
    $client->generations()->retrieve('task_id');
} catch (ApiException $error) {
    echo $error->statusCode . PHP_EOL;
    echo $error->apiCode . PHP_EOL;
    echo $error->getMessage() . PHP_EOL;
    print_r($error->details);
}

try {
    $client->generations()->wait('task_id');
} catch (GenerationFailedException $error) {
    print_r($error->task['error'] ?? null);
}

Development

cd php
composer validate --strict
composer install
composer test
composer analyse
composer cs

Live smoke test:

BUBLE_API_KEY=sk_... php tools/live-smoke.php

The live smoke test calls discovery endpoints only and does not create billable generation tasks.

Publishing Checklist

Packagist package identity:

  • Package name: buble/sdk
  • Namespace: Buble\
  • License: MIT
  • Homepage: https://buble.ai/

Because this repository is a multi-language monorepo, publish the PHP SDK through a PHP-only split repository rather than submitting the monorepo root to Packagist:

git subtree split --prefix=php -b php-release
git push git@github.com:bublehq/php-sdk.git php-release:main --force-with-lease

Create and push a release tag in the PHP-only repository:

git tag v0.1.0
git push origin v0.1.0

Submit the PHP-only repository to Packagist:

https://github.com/bublehq/php-sdk

Configure the GitHub/Packagist hook so new tags are indexed automatically. Composer package versions are immutable once tagged; fixes after v0.1.0 should use a new tag such as v0.1.1.