werstreamtes / targetvideo-cms-client
Unofficial PHP client for the Target Video CMS API v3.
Package info
github.com/werstreamtes/targetvideo-cms-client
pkg:composer/werstreamtes/targetvideo-cms-client
Requires
- php: ^8.1
- ext-json: *
- psr/http-client: ^1.0
- psr/http-factory: ^1.1
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- phpunit/phpunit: ^11.5
Suggests
- ext-curl: Use the default built-in cURL transport.
- guzzlehttp/guzzle: Use Guzzle as the PSR-18 transport implementation.
- guzzlehttp/psr7: Use Guzzle's PSR-7 and PSR-17 implementation with the PSR-18 transport.
- nyholm/psr7: Lightweight PSR-7 and PSR-17 implementation for the PSR-18 transport.
- symfony/http-client: Use Symfony HttpClient as the PSR-18 transport implementation.
- symfony/psr-http-client-bridge: Bridge Symfony HttpClient to PSR-18.
This package is auto-updated.
Last update: 2026-07-28 08:24:26 UTC
README
Unofficial PHP client for the Target Video CMS API v3.
This package is not affiliated with, endorsed by, or maintained by Target Video.
Overview
- Bearer-token authenticated client for
https://api.target-video.com/apiv3 - Typed API for common video and category management tasks
- Raw resource API for endpoints that do not have typed wrappers yet
- Default cURL transport plus optional PSR-18 transport support
- Automatic request encoding for
multipart/form-dataandapplication/x-www-form-urlencoded - Notes for verified live API behavior that differs from the published docs: docs/live-api-differences.md
Installation
composer require werstreamtes/targetvideo-cms-client
The default transport uses PHP's curl extension. If your runtime does not provide curl, use a PSR-18 HTTP client instead.
Getting Started
<?php require 'vendor/autoload.php'; use Werstreamtes\TargetVideoCmsClient\CmsClient; use Werstreamtes\TargetVideoCmsClient\Config; $client = new CmsClient(new Config( bearerToken: 'YOUR_TARGETVIDEO_BEARER_TOKEN', )); $videos = $client->videos()->all( partnerId: 12345, queryParameters: [ 'page' => 1, 'limit' => 25, ], ); foreach ($videos->entries() as $entry) { echo $entry->videoId() . ': ' . ($entry->videoName() ?? 'unnamed') . PHP_EOL; }
Video API
<?php use Werstreamtes\TargetVideoCmsClient\Video\AddVideoRequest; use Werstreamtes\TargetVideoCmsClient\Video\EditVideoRequest; use Werstreamtes\TargetVideoCmsClient\Video\VideoCustomProperty; $videos = $client->videos(); $created = $videos->add(new AddVideoRequest( partnerId: 12345, name: 'Example Video', sourceUrl: 'https://cdn.example.com/video.mp4', description: 'Created through the typed video API', credits: 'Reuters', tags: 'example,typed-client', customProperties: [ new VideoCustomProperty('slot', 'pre-roll'), ], )); $video = $videos->view($created->videoId()); $videos->edit($video->id(), new EditVideoRequest( name: 'Renamed Example Video', description: 'Updated description', credits: 'AP', clickthroughUrl: 'https://example.com/watch/' . $video->id(), customProperties: [ new VideoCustomProperty('slot', 'mid-roll'), ], )); $videos->delete($video->id(), 12345);
Category API
Category endpoints are available in the live API but are currently missing from the public Target Video docs index. They are supported from a Target Video Support-provided Postman collection and verified against the live API.
<?php use Werstreamtes\TargetVideoCmsClient\Category\AddCategoryRequest; use Werstreamtes\TargetVideoCmsClient\Category\AssignVideosRequest; use Werstreamtes\TargetVideoCmsClient\Category\EditCategoryRequest; $categories = $client->categories(); $categoryList = $categories->all(parentId: 0, queryParameters: ['page' => 1]); foreach ($categoryList->entries() as $entry) { echo $entry->categoryId() . ': ' . ($entry->categoryName() ?? 'unnamed') . PHP_EOL; } $createdCategory = $categories->add(new AddCategoryRequest( name: 'Example Category', )); $category = $categories->view($createdCategory->categoryId()); $categories->edit($category->id(), new EditCategoryRequest( name: 'Renamed Example Category', parentId: 0, )); $categories->assignVideos(new AssignVideosRequest( categoryIds: [$category->id()], videoIds: [540690], )); $categories->delete($category->id());
Raw Resource API
Use the raw API when a typed method does not exist yet or when you need direct control over Target Video's request shape.
<?php $adSources = $client->adSources()->call( 'all', pathParameters: ['partner_id' => 12345], ); $video = $client->resource('video')->call( 'view', pathParameters: ['video_id' => 540690], ); $createdVideo = $client->resource('video')->call( 'add', bodyParameters: [ 'partner_id' => 12345, 'name' => 'Example Video', 'mp4' => 'https://cdn.example.com/video.mp4', ], ); $updatedVideo = $client->resource('video')->call( 'edit', pathParameters: ['video_id' => 540690], bodyParameters: [ 'Video' => [ 'name' => 'Renamed Example Video', 'description' => 'Updated description from the API client', 'clickthroughUrl' => 'https://example.com/watch/540690', ], ], ); $analytics = $client->callOperation( 'Topvideosdata', pathParameters: ['partner_id' => 12345], bodyParameters: [ 'from' => '2026-06-01', 'to' => '2026-06-16', ], );
For actions that are ambiguous inside a resource, use callOperation() with the exact operation ID from the operation catalog.
PSR-18 Transport
Install a PSR-18 client if you do not want to use the default cURL transport:
composer require guzzlehttp/guzzle guzzlehttp/psr7
<?php use GuzzleHttp\Client as GuzzleClient; use GuzzleHttp\Psr7\HttpFactory; use Werstreamtes\TargetVideoCmsClient\CmsClient; use Werstreamtes\TargetVideoCmsClient\Config; $httpClient = new GuzzleClient(); $httpFactory = new HttpFactory(); $client = CmsClient::withPsr18( config: new Config(bearerToken: 'YOUR_TARGETVIDEO_BEARER_TOKEN'), httpClient: $httpClient, requestFactory: $httpFactory, streamFactory: $httpFactory, );
Per-request transport options are intentionally transport-specific. With the PSR-18 transport, configure timeouts and retries on the injected HTTP client.
Supported Entry Points
Typed entry points:
$client->videos(); $client->categories();
Common raw resource helpers:
$client->adSchedules(); $client->adSources(); $client->adUnits(); $client->adUnitTemplates(); $client->analytics(); $client->carousel(); $client->categories(); $client->exchangeRules(); $client->iabTaxonomies(); $client->livestreamChannel(); $client->livestreamSchedule(); $client->partners(); $client->players(); $client->playerTemplates(); $client->playlists(); $client->revenueDashboard(); $client->users(); $client->resource('video'); $client->resource('videos'); $client->resource('category'); $client->resource('categories'); $client->resource('adSources');
Documentation Notes
The client is based on the public Target Video CMS reference and additional live API verification:
Known live API differences include:
video/editacceptsVideo[description]even though the published edit reference omits it.video/addandvideo/editacceptcreditseven though the published docs do not document that field.video/addsucceeds withoutchannel_ideven though the request example labels it as required.video/allacceptspageandlimiteven though the published query parameter list omits them.- Category management endpoints are available in the live API but are not listed in the published documentation index.
Development
This section is for contributors to this package, not for normal package users.
Build the PHP toolchain:
docker compose build
Validate Composer metadata, lint PHP files, and run unit tests:
docker compose run --rm php composer validate --strict
docker compose run --rm php composer lint
docker compose run --rm php composer test
Regenerate the operation catalog from the live docs:
docker compose run --rm php php tools/generate-operations.php
When regenerating the operation catalog, re-verify every entry in docs/live-api-differences.md.
Integration Tests
Live integration tests call the real Target Video API. Credentials are loaded from .env by Docker Compose.
Read-only integration tests:
TARGETVIDEO_TEST_BEARER_TOKEN="your-token" \ TARGETVIDEO_TEST_PARTNER_ID="12345" \ docker compose run --rm php composer test:integration
Write integration tests create disposable videos, edit metadata/custom properties, verify the updated values through video/view, and delete the videos again.
TARGETVIDEO_TEST_BEARER_TOKEN="your-token" \ TARGETVIDEO_TEST_PARTNER_ID="12345" \ TARGETVIDEO_TEST_ENABLE_WRITE_TESTS="1" \ docker compose run --rm php composer test:integration-write
If the partner account has no existing videos, set TARGETVIDEO_TEST_VIDEO_SOURCE_URL explicitly so the write suite has a source video URL to import. TARGETVIDEO_TEST_CHANNEL_ID is optional.
Releasing
Packagist versions are created from Git tags, not from a version field in composer.json.
git tag v0.1.0 git push origin main --tags
After the GitHub repository is connected to Packagist, new tags become installable Composer versions.