PRE-GEN
Docs / C2PA integration

PRE-GEN assertions in C2PA manifests

Status: spec draft · Assertion marker: pg.assertion.v1 · C2PA: 1.x

C2PA answers “who made this and when”. It does not answer “were they allowed to”. PRE-GEN bridges the gap with pg.assertion.v1 — a signed authorization assertion embedded directly into a C2PA manifest, so the permission travels inside the file instead of living in a database somewhere. Content and its consent become inseparable.

Division of labor C2PA is provenance. PRE-GEN is authorization. An assertion is not a license — it is a verifiable pointer to one. Anyone can resolve the PG codes and check the signatures against the registry’s public keys, independently of the file’s author.

What goes into the assertion

pg.assertion.v1 is a C2PA custom assertion (action array stays untouched; PRE-GEN data rides in a com.pregen.authorization/1 assertion). Canonical JSON, no floats, signature excluded from its own signed bytes:

{
  "v": "pg.assertion.v1",
  "subject_pg": "PG-000042*",
  "decision_ref": {
    "decision_id": "dec_01J8ZK…",
    "registry": "https://api2.prampta.com",
    "decided_at": 1787600000,
    "decision_sig": "a3f1…"
  },
  "license_pg": "PG-STD-000042-K7M2QX9",
  "provider_id": "prov_studio_one",
  "receipt_ref": "rcp_01J8ZM…",
  "generated_at": 1787600123
}
FieldMeaning
subject_pgThe subject depicted — resolvable at /lookup
decision_refPointer to the signed allow-decision: id, registry base URL, timestamp, decision signature
license_pgThe license that backed the decision (optional in opt-out denials)
receipt_refThe provider’s post-generation receipt tying output to decision

Embedding

Use any C2PA-conformant SDK (the CAI c2pa-rs, Python c2pa-python, or a hosted SDK). The assertion is added as a custom assertion before signing:

from prampta import Prampta
from c2pa import C2paReader, C2paWriter   # illustrative

pg = Prampta(base_url="https://api2.prampta.com", …)
decision = pg.assert_allowed("PG-000042*", prompt=prompt, modality="image")

assertion = pg.c2pa_assertion(decision)   # builds pg.assertion.v1
writer.add_assertion("com.pregen.authorization/1", assertion)
writer.sign(...)                           # your C2PA credential

The PRE-GEN assertion never replaces the C2PA signature — it sits alongside it. Stripping the assertion breaks the studio’s chain-of-title check; stripping the C2PA signature invalidates the manifest. Both tamper paths are visible.

Verification, from anywhere

  1. Read the manifest, find com.pregen.authorization/1.
  2. Resolve subject_pg publicly — pregen.org/lookup or GET /v1/subjects/{code}.
  3. Fetch the registry’s key set (GET /keys, rotation-aware) and verify decision_sig over the canonical decision bytes.
  4. Optionally pull the evidence bundle and walk the audit chain back to genesis.

No account, no SDK required — the file carries everything needed to ask the registry “was this authorized?” and check the answer cryptographically.

What this is not

An assertion is evidence, not permission. The permission is the license; the assertion proves which license applied and that the provider asked. It also says nothing about provenance of the input material — that remains C2PA’s job. The two layers are complementary by design: C2PA for origin, PRE-GEN for consent.