Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Zencoder Php Laravel Package

zencoder/zencoder-php

zencoder/zencoder-php is a PHP client for the Zencoder video encoding API. It simplifies submitting transcoding jobs, managing outputs, tracking progress, handling notifications, and integrating cloud video encoding into Laravel or standalone PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a thin, static-style PHP wrapper around the Zencoder REST API (video/audio transcoding as a service). There is no Laravel service provider, no config file, and no facades — you wire it up yourself in a few lines.

Install

composer require zencoder/zencoder-php

If Packagist resolution fails (the upstream repo is brightcove-archive/zencoder_php, archived under Brightcove), point Composer at the VCS URL and pin a commit. Do this deliberately — see Gotchas.

Configure

Set the API key once at boot (a service provider boot() or a dedicated bootstrap file works), not in the middle of controllers:

// app/Providers/AppServiceProvider.php
public function boot(): void
{
    \Zencoder::setApiKey(config('services.zencoder.key'));
}

First use case — encode one upload to H.264 + poster frame

This is the 80% scenario: user uploads a source file, you want a web-ready MP4 and a thumbnail.

$job = \Zencoder::jobs()->create([
    'input'  => 's3://my-bucket/uploads/source.mov',
    'outputs' => [[
        'label'    => 'web-720p',
        'format'   => 'mp4',
        'width'    => 1280,
        'height'   => 720,
        'public'   => true,
        'thumbnails' => [
            'number' => 3,
            'size'   => '1280x720',
            'base64' => false,
        ],
    ]],
]);

Then read the job back via \Zencoder::jobs()->details($job->id) (or the Zencoder_Job object the library returns, which already carries outputs[].url once finished).

Where to look first

  1. The README's request/response examples — the API shape mirrors the JSON body verbatim, so Zencoder_Output docblocks are your best field reference.
  2. The tests/ directory — it's the only documentation of return-object structure and error behavior.
  3. Zencoder's own zencoder.com/docs API reference (archived via Wayback) for valid outputs[] keys, since the PHP library validates nothing.

Implementation Patterns

Wrap it in one domain service. Never let controllers see \Zencoder:: statics. A single VideoEncoder class gives you a seam to mock, and lets you swap to a self-hosted encoder later without touching call sites.

class VideoEncoder
{
    public function submit(string $sourceUrl, array $presets): EncodedJob
    {
        $response = \Zencoder::jobs()->create([
            'input'              => $sourceUrl,
            'outputs'            => $presets,
            'notifications'      => [route('webhooks.zencoder')],
            'pass_through'       => ['tenant_id' => tenant()->id],
        ]);

        return EncodedJob::create([
            'zencoder_id' => $response->id,
            'status'      => 'submitted',
        ]);
    }
}

Persist the job id and poll as a backstop. The idiomatic Zencoder flow is webhook-driven, but webhooks get lost. Store zencoder_id, then run a scheduled command every 5–10 minutes that calls jobs()->details($id) for anything still processing and reconciles. Treat the webhook as the fast path and the poller as the source of truth.

Webhook endpoint. Zencoder POSTs a job JSON body. Verify by job id (there's no HMAC signature in the classic API), then reconcile:

Route::post('/webhooks/zencoder', function (Request $request) {
    $job = EncodedJob::where('zencoder_id', $request->input('job.id'))->firstOrFail();

    match ($request->input('job.state')) {
        'finished' => $job->markReady($request->input('job.output_media_files')),
        'failed'   => $job->markFailed($request->input('job.failure_reason')),
        'cancelled'=> $job->markCancelled(),
        default    => null,
    };

    return response()->noContent();
});

Exclude this route from CSRF and from auth middleware.

Presets live in config, not code. Output arrays are bulky and change per product surface (web, mobile, social). Put them in config/encoding.php keyed by name, and build the outputs array from a preset name. Avoid hitting Zencoder's preset API on every request — cache it.

Queue the submission. Job creation is an outbound HTTP call that can take a second or more. Dispatch a queued job (SubmitEncodingJob) so upload UX isn't blocked, and give it tries = 3 with exponential backoff for 5xx responses.

Multi-output jobs for one input. Submitting one job with several outputs (MP4 720p, MP4 360p, HLS, thumbnails) is cheaper and faster than multiple jobs — the input is downloaded and demuxed once.

Gotchas and Tips

It's archived and the service is on borrowed time. Brightcove wound Zencoder down; the repo is read-only. Before building anything, confirm you have API credentials and a contract. If you don't, this package is a dead end regardless of code quality — treat any adoption as maintenance of a legacy integration, not a greenfield choice.

Fully static global state. setApiKey() mutates a static — it leaks between tests, between tenants, and across long-running workers. Workarounds: call setApiKey() again before each dispatch to a given tenant's key, and in tests reset it in setUp().

No namespacing, no PSR-4 autoloading. Classes are global (Zencoder_Job, Zencoder_Output). In a Laravel app that already has App\Job, App\Output etc., this is fine, but IDE autocomplete and static analysis will be weaker. Add a @method docblock on your wrapper class to restore type hints.

Errors come back as HTTP status + JSON, not exceptions. A 422 (bad output setting) and a 403 (bad key) both look like a returned object with an errors array. Always check before assuming success:

$response = \Zencoder::jobs()->create($payload);

if (!empty($response->errors)) {
    throw new EncodingException($response->errors);
}

A silent no-op here is the most common cause of "jobs never appear in the dashboard."

No retry, no timeout, no connection pooling. The cURL call is synchronous and defaulted. If you're submitting in a request cycle, you'll get slow responses on network hiccups. Set a curl timeout via CURLOPT_* if the class exposes options, or just always queue.

Webhook delivery is at-least-once and out of order. A finished callback can arrive twice, or a processing can land after finished on retries. Make your handler idempotent and never move a job backward out of a terminal state.

Source must be reachable by Zencoder, not by you. s3:// requires a bucket policy that grants Zencoder read access, or a signed URL. Local storage/app paths won't work. Signed S3 URLs expire — a queued job that sits for hours in a retry loop can fail with a 404 on the input for this reason.

Output destinations need write credentials. Set the S3 output credentials once at account level in the dashboard rather than per job; embedding keys in job payloads puts them in logs.

Rate and concurrency limits are account-level. Free/trial tiers cap concurrent jobs; exceeding it returns 429. Queue submissions and throttle — don't fan out 200 jobs in a foreach.

Extension point is the API, not the class. When you need HLS manifests, DRM, or clipping, you'll be adding raw outputs[] keys anyway. Don't subclass; keep the wrapper dumb and put your logic in the service layer so it survives a rewrite.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource