Unofficial PHP client for the Target Video CMS API v3.
This package is not affiliated with, endorsed by, or maintained by Target Video.
- 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
composer require werstreamtes/targetvideo-cms-clientThe default transport uses PHP's curl extension. If your runtime does not provide curl, use a PSR-18 HTTP client instead.
<?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;
}<?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 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());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.
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.
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');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.
This section is for contributors to this package, not for normal package users.
Build the PHP toolchain:
docker compose buildValidate 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 testRegenerate the operation catalog from the live docs:
docker compose run --rm php php tools/generate-operations.phpWhen regenerating the operation catalog, re-verify every entry in docs/live-api-differences.md.
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:integrationWrite 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-writeIf 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.
Packagist versions are created from Git tags, not from a version field in composer.json.
git tag v0.1.0
git push origin main --tagsAfter the GitHub repository is connected to Packagist, new tags become installable Composer versions.