Skip to content

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.

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.

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;.


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-uuid
Files.write(Path.of("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. 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());
}
}

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 high
if (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.

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.


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()}")

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());
}
}

var overview = client.analyticsOverview(30); // lookback days (null = default)
var page = client.auditLog(1, 20); // page, limit
var 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 signatures

Enterprise plans can pull an EU AI Act compliance attestation:

var att = client.attestation(null, null); // default last-90-days window
String 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).