EU AI Act Provenance & Label API

Read, verify and report C2PA Content Credentials on any uploaded file — so a platform can prove it checked, and flag what arrived unlabelled.

Article 50 · in force 2 Aug 2026 Deterministic · no PKI required MIT / Apache-2.0 tooling Public & free

Not legal advice. Not an official EU or C2PA service. A passing verdict is not a compliance guarantee. Absence of a credential is not proof content is not AI-generated — manifests are routinely stripped by screenshots, re-encoding, and CDN transforms. This is a provenance verifier, not a deepfake detector: every AI-generation signal comes from a signed C2PA assertion.

Live verifier

Drop a file to verify it against this API. The bytes are hashed and checked; they are never stored.

or drop it here

Verdicts

labelledA C2PA credential is present and validates.
unlabelledNo verifiable credential found. Not proof of anything about AI.
invalidA credential is present but validation failed.
indeterminateUnsupported type, or the engine errored/timed out.

Validation state distinguishes Trusted (signer on a known trust list) from Valid (cryptographically intact but unknown signer). AI signal (aiInferred) is one of ai-generated, ai-edited, not-declared, unknown.

Endpoints

POST /v1/verify

Verify one asset → verdict + manifest summary + signed audit record.

# multipart upload
curl -s -X POST "$BASE/v1/verify" -F "file=@photo.jpg"

# by URL
curl -s -X POST "$BASE/v1/verify" \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com/image.jpg"}'
// fetch (browser)
const fd = new FormData();
fd.append("file", fileInput.files[0]);
const r = await fetch("/c2pa/v1/verify", { method: "POST", body: fd });
const { verdict, aiInferred, audit } = await r.json();

POST /v1/verify/batch

curl -s -X POST "$BASE/v1/verify/batch" \
  -H "content-type: application/json" \
  -d '{"assets":[{"id":"a","url":"https://ex.com/1.jpg"},{"id":"b","url":"https://ex.com/2.png"}]}'

POST /v1/report

Full parsed manifest store + raw C2PA validation_results (for display/debugging).

GET /v1/audit/{recordId} · GET /v1/usage

Retrieve a retained audit record (API-key holders) and see your usage/quota.

Static (no auth): /api/v1/*

index.json · meta.json · formats.json · status-codes.json · audit-key.json · openapi.yaml

Signed audit record

Every verify returns a tamper-evident record — asset hash, verdict, trust-list & engine versions, timestamp — signed with the service key. Verify it offline with the public key at /api/v1/audit-key.json and the @c2pa-provenance/lib verifyAuditRecord() helper. No asset bytes are ever stored.

Access & rate limits

Public and free. Anonymous callers get 60 req/min and 5,000/day per IP; an optional API key raises that and retains audit history. Over-limit returns 429 with Retry-After. Uploads over the size cap return 413; images with any side over 8000px return 400.