Skip to content

PHP SDK

The certivu/sdk package is a synchronous, thin REST client for signing and verifying AI-generated content from PHP. It targets web apps, CMS plugins, and content pipelines wiring POST /v1/verify into upload and moderation flows — plus generator-side backends.

Like every Certivu SDK, it does no client-side cryptography. Signing happens server-side (org private keys and signing quota live behind the API) and verification goes through the API. The SDK never bundles ML-DSA.

The SDK ships from cdn.certivu.ai as a static Composer repository — not from Packagist or a public GitHub repo (the monorepo is private). A static Composer repo is just files over HTTPS, so the CDN serves the whole thing.

Add the repository and requirement to your composer.json:

{
"repositories": [
{ "type": "composer", "url": "https://cdn.certivu.ai/sdk/php" }
],
"require": {
"certivu/sdk": "^1.0"
}
}

Then composer update certivu/sdk.

Requires PHP 8.1+ with the curl and json extensions (both standard). The SDK has zero Composer dependencies. It versions on its own line (starting 1.0.0), independent of the platform version.

$client = new Certivu\Client(
'ctv_key_abc123', // pass '' for verify-only
generatorId: 'your-generator-uuid', // required for signing
);

Constructor signature: new Certivu\Client($apiKey, $baseUrl, $generatorId, $timeout). Use named arguments to skip $baseUrl — point it at the sandbox when needed. $timeout defaults to 60s. sign() and verify() return typed objects; every read endpoint returns a decoded associative array.


$img = file_get_contents('output.png'); // or .mp3, .mp4, .pdf, etc.
$res = $client->sign($img, 'stable-diffusion-xl');
echo $res->token . "\n"; // ctv_7f3kx9mq2...
echo $res->recordId . "\n"; // rec-uuid
file_put_contents('output.signed.png', $res->signedContent); // store THIS

$res->signedContent is the signed content with the ctv_ token injected into a format-native container (XMP, ID3v2, HTML meta, cerv atom, …) and the watermark embedded — deliver it instead of the original. Pass a fourth argument to override the format: $client->sign($img, 'sdxl', generatorId: null, format: 'image').

When the API recognises identical input bytes it re-uses the existing record without charging a new signature; $res->deduplicated is then true.

$results = $client->signBatch([
['content' => $a, 'model' => 'sdxl'],
['content' => $b, 'model' => 'sdxl', 'format' => 'image'],
]);
foreach ($results as $r) {
if (isset($r['result'])) {
echo $r['result']->token . "\n";
} else {
fwrite(STDERR, "item failed: " . $r['error']->getMessage() . "\n");
}
}

Verification is free, unlimited, and needs no API key — construct a verify-only client with an empty key:

$client = new Certivu\Client('');
$res = $client->verify($contentBytes);
echo ($res->authentic ? 'true' : 'false') . " {$res->confidence}\n"; // e.g. true high
if ($res->provenance !== null) {
echo "signed by {$res->provenance['org']} using {$res->provenance['model']}\n";
}

Pass a token as the second argument — $client->verify($content, 'ctv_...') — to take the fast path when you already hold it. Verification works on transformed copies (resized, recompressed, reposted) via watermark, pHash, and fingerprint recovery.

$status = $client->tokenStatus('ctv_...'); // associative array
echo "{$status['model']} {$status['generator_status']} {$status['org_name']}\n";

This CDN-cacheable lookup powers badges and certificate pages without re-hashing content.


Any non-2xx response throws Certivu\ApiException (a subclass of Certivu\CertivuException). Branch with the predicate helpers:

use Certivu\ApiException;
try {
$client->sign($img, 'sdxl');
} catch (ApiException $e) {
if ($e->isQuota()) { // 402 — free-tier signing limit
echo "upgrade at {$e->upgradeUrl()}\n";
} elseif ($e->isAuth()) { // 401 — bad / missing key
echo "invalid API key\n";
} elseif ($e->isValidation()) { // 400
echo $e->getMessage() . "\n";
} else {
echo "certivu error {$e->status()}: {$e->getMessage()}\n";
}
}

Read endpoints return decoded associative arrays:

$overview = $client->analyticsOverview(30); // lookback days (null = default)
$page = $client->auditLog(1, 20); // page, limit
$rec = $client->recordAnalytics('rec-uuid'); // Growth+
$wh = $client->createWebhook('https://hooks.example/certivu', ['tamper.detected']);
echo $wh['secret'] . "\n"; // shown ONCE — store it to verify delivery signatures

Enterprise plans can pull an EU AI Act compliance attestation:

$att = $client->attestation(); // default last-90-days window
$html = $client->exportAttestation('html'); // rendered document string

  • No client crypto. Signing and verification are both API calls; offline verification is not supported.
  • Zero Composer dependencies. PHP 8.1+ with ext-curl and ext-json.
  • Default timeout is 60s (server-side watermarking takes a moment). Override via the timeout: constructor argument.
  • Distributed as a static Composer repository at https://cdn.certivu.ai/sdk/php (no Packagist, no GitHub).