Java SDK
The ai.certivu:certivu artifact is a synchronous, thin REST client for signing and verifying AI-generated content on the JVM. It targets Java and Kotlin backends wiring POST /v1/verify into content ingest, moderation, and CI — plus generator-side services.
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.
Install
Section titled “Install”The SDK ships from cdn.certivu.ai as a static Maven repository — not from Maven Central or a public GitHub repo (the monorepo is private). A static Maven repo is just files over HTTPS, so the CDN serves the whole thing.
Add the repository, then the dependency. Gradle:
repositories { mavenCentral() maven { url "https://cdn.certivu.ai/sdk/maven" }}
dependencies { implementation "ai.certivu:certivu:1.0.0"}Maven (pom.xml):
<repositories> <repository> <id>certivu</id> <url>https://cdn.certivu.ai/sdk/maven</url> </repository></repositories>
<dependency> <groupId>ai.certivu</groupId> <artifactId>certivu</artifactId> <version>1.0.0</version></dependency>Requires Java 17+. One runtime dependency: Gson. The artifact versions on its own line (starting 1.0.0), independent of the platform version.
Initialize
Section titled “Initialize”CertivuClient client = CertivuClient.builder("ctv_key_abc123") // pass "" for verify-only .generatorId("your-generator-uuid") // required for signing .build();Builder options: baseUrl(url) (point at the sandbox), generatorId(id), timeout(Duration) (default 60s), and httpClient(HttpClient) to supply your own. Instances are immutable and safe to share across threads. Use CertivuClient.create("") for the common verify-only case.
Response types are nested records under Models — import them directly, e.g. import ai.certivu.Models.SignResult;.
Sign content
Section titled “Sign content”byte[] img = Files.readAllBytes(Path.of("output.png")); // or .mp3, .mp4, .pdf, etc.
SignResult res = client.sign(img, "stable-diffusion-xl");
System.out.println(res.token()); // ctv_7f3kx9mq2...System.out.println(res.recordId()); // rec-uuidFiles.write(Path.of("output.signed.png"), res.signedContent()); // store THISres.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. Use client.sign(content, model, new SignOptions("gen-id", "image")) to override the format or generator.
When the API recognises identical input bytes it re-uses the existing record without charging a new signature; res.deduplicated() is then true.
import ai.certivu.Models.SignItem;import ai.certivu.Models.SignBatchResult;
var results = client.signBatch(List.of( new SignItem(a, "sdxl"), new SignItem(b, "sdxl", "image")));for (SignBatchResult r : results) { if (r.isOk()) { System.out.println(r.result().token()); } else { System.err.println("item failed: " + r.error().getMessage()); }}Verify content
Section titled “Verify content”Verification is free, unlimited, and needs no API key — construct a verify-only client with an empty key:
CertivuClient client = CertivuClient.create("");
VerifyResult res = client.verify(contentBytes);System.out.println(res.authentic() + " " + res.confidence()); // e.g. true highif (res.provenance() != null) { System.out.printf("signed by %s using %s%n", res.provenance().org(), res.provenance().model());}Use client.verify(content, "ctv_...") to take the fast path when you already hold the token. Verification works on transformed copies (resized, recompressed, reposted) via watermark, pHash, and fingerprint recovery.
Token status (no upload)
Section titled “Token status (no upload)”var status = client.tokenStatus("ctv_...");System.out.println(status.model() + " " + status.generatorStatus() + " " + status.orgName());This CDN-cacheable lookup powers badges and certificate pages without re-hashing content.
Kotlin
Section titled “Kotlin”The SDK is idiomatic from Kotlin — records expose accessor methods:
val client = CertivuClient.builder(System.getenv("CERTIVU_API_KEY")) .generatorId(System.getenv("CERTIVU_GENERATOR_ID")) .build()
val signed = client.sign(File("image.png").readBytes(), "stable-diffusion-xl")File("image.signed.png").writeBytes(signed.signedContent())
val result = client.verify(signed.signedContent())println("authentic: ${result.authentic()} confidence: ${result.confidence()}")Error handling
Section titled “Error handling”Any non-2xx response throws ApiException (a subclass of CertivuException). Branch with the predicate helpers:
import ai.certivu.ApiException;
try { client.sign(img, "sdxl");} catch (ApiException e) { if (e.isQuota()) { // 402 — free-tier signing limit System.out.println("upgrade at " + e.upgradeUrl()); } else if (e.isAuth()) { // 401 — bad / missing key System.out.println("invalid API key"); } else if (e.isValidation()) { // 400 System.out.println(e.getMessage()); } else { System.out.println("certivu error " + e.status() + ": " + e.getMessage()); }}Analytics, audit, webhooks
Section titled “Analytics, audit, webhooks”var overview = client.analyticsOverview(30); // lookback days (null = default)var page = client.auditLog(1, 20); // page, limitvar rec = client.recordAnalytics("rec-uuid"); // Growth+
var wh = client.createWebhook("https://hooks.example/certivu", List.of("tamper.detected"));System.out.println(wh.secret()); // shown ONCE — store it to verify delivery signaturesEnterprise plans can pull an EU AI Act compliance attestation:
var att = client.attestation(null, null); // default last-90-days windowString html = client.exportAttestation("html", null, null); // rendered document string- No client crypto. Signing and verification are both API calls; offline verification is not supported.
- One dependency (Gson); requires Java 17+. Instances are immutable and safe to share across threads.
- Distributed as a static Maven repository at
https://cdn.certivu.ai/sdk/maven(no Maven Central, no GitHub).