Permission → Provenance — Authorization Binding
This page documents VoiceSeal's closed loop: when a synthesis is authorized, the marked file's C2PA manifest carries durable, pseudonymous references that anyone can resolve — with no credentials — back to a non-PII authorization attestation. Every value below was captured from a live production round-trip, and the resolver reference is verifiable right now (§5).
Live round-trip captured 2026‑09‑10 from production (api.voiceseal.io). The check_id shown is a real record; the resolver call in §5 returns its current attestation.
1.What the closed loop proves
A third party who receives a marked audio file can answer one question without contacting VoiceSeal and without any account: "Was this synthesis authorized?"
They read the file's io.voiceseal.c2pa C2PA assertion, take the check_id and resolver URL it contains, and call the public resolver. The resolver returns a non-PII attestation — authorized or not, the licence status, and when it was authorized. The reference in the file is an opaque UUID; the sensitive facts (who, consent, biometric, the authorization token) never leave VoiceSeal and are never in the file.
This is the provenance-side complement to the signing evidence on the C2PA transparency page: that page proves the signature is trusted and the content is intact; this page proves the authorization is bound to the file and independently checkable.
2.The round-trip (live production values)
Captured from the production API on 2026‑09‑10. This is the same flow the loop always follows — authorize, get a one-time token, mark, validate, resolve.
- Authorize —
POST /api/v1/protect/pre-synthesis-check(authenticated, with a valid licence) returns a decision and acheck_id.action authorized decision allow check_id 9812af23-8e25-4928-b3b6-6a67b0595d2d - Token —
POST /api/v1/provenance/synthesis-tokenissues a one-time synthesis-authorization token carrying thecheck_idandlicense_id(the token itself is never embedded). - Mark —
POST /api/v1/provenance/mark-synthetic-audio(audio + token) returns the signed WAV. Response headers from production:x-authorization-binding applied APPLIED x-signer trufo x-signer-trusted true x-provenance c2pa.ai-disclosure - Validate — the returned file, checked against the official C2PA trust anchors (§3).
- Resolve — the public resolver, called with the
check_idfrom the manifest (§5).
3.The file still validates trusted
This is the mandatory check: the authorization binding must not weaken the signature. Validated with the C2PA SDK against the official trust list (the same trust anchors as the C2PA page):
| validation_state | Trusted TRUSTED |
| trust_validated | true |
| integrity_valid / tampered | true / false |
| validation_failures | [] (none) |
| signer issuer | Trufo Inc. |
| assertion labels | c2pa.actions.v2, ai.trufo.identity, io.voiceseal.c2pa, c2pa.ai-disclosure |
Validator success codes on the signed file:
- ✓
signingCredential.trusted - ✓
timeStamp.trusted/timeStamp.validated - ✓
claimSignature.validated - ✓
assertion.dataHash.match(content intact)
4.The embedded assertion (as signed)
The io.voiceseal.c2pa custom assertion carried in the marked file — exactly as it appears in the manifest. Its label is the reverse-DNS form of VoiceSeal's domain-validated C2PA custom domain (c2pa.voiceseal.io), per the C2PA convention for third-party assertions.
{
"label": "io.voiceseal.c2pa",
"data": {
"check_id": "9812af23-8e25-4928-b3b6-6a67b0595d2d",
"license_id": "a816f3fb-6988-4709-9fe8-f5d131a69e61",
"resolver": "https://api.voiceseal.io/api/v1/provenance/resolve/{check_id}",
"voice_id": "unspecified",
"generation_job_id": "unspecified",
"tts_provider": "VoiceSeal Live Artifact",
"tts_model": "live-demo-v1",
"marked_by": "VoiceSeal synthetic-marking gateway"
}
}
tts_provider/tts_model here identify this demonstration mark. On the one-time-token marking path voice_id is recorded as unspecified — the token carries the check_id, and the voice is resolved from the check_id server-side at the resolver, so the durable references that bind the file are check_id and license_id.
5.What is deliberately NOT in the file
The manifest and the resolver are both publicly readable, so they carry only opaque, pseudonymous UUIDs. A scan of the signed manifest confirms none of the following is present:
- ✗ the authorization token (an ephemeral, single-use credential)
- ✗ the consent record
- ✗ any biometric / voiceprint / embedding
- ✗ the requester's email, the owner's identity, or any account id
- ✗ the licence token string
Verified by a leak scan over the full manifest of the signed file: all of the above — absent. The file carries check_id, license_id, and the resolver URL, and nothing that identifies a person.
6.Verify it yourself
The resolver is public (rate-limited, no auth). Take the check_id from a marked file's io.voiceseal.c2pa assertion and call:
# Resolve the authorization reference from the manifest above curl -s https://api.voiceseal.io/api/v1/provenance/resolve/9812af23-8e25-4928-b3b6-6a67b0595d2d
It returns the non-PII attestation for that exact check — currently:
{
"authorized": true,
"decision": "allow",
"license_status": "active",
"voice_public_alias": null,
"authorized_at": "2026-09-10T13:23:14.818147",
"in_scope": true,
"check_id": "9812af23-8e25-4928-b3b6-6a67b0595d2d"
}
An unknown, malformed, or non-existent id returns an honest no record rather than an error:
curl -s https://api.voiceseal.io/api/v1/provenance/resolve/00000000-0000-0000-0000-000000000000
# -> { "authorized": false, "reason": "no record", "check_id": "00000000-0000-0000-0000-000000000000" }
check_ids are UUIDv4 (not sequential, not enumerable); the resolver is rate-limited as anti-abuse. Revoked or expired licences are reflected in license_status, so the attestation tracks the current authorization state, not a frozen snapshot.
7.Notes & limitations (stated plainly)
- The binding rides in the same in-band C2PA manifest described on the C2PA transparency page. As noted there, C2PA is tamper-evident but not indestructible: downstream transcoding or deliberate metadata stripping can detach the credential (and with it the binding) from the media.
- The
c2pa.ai-disclosurein the file is still the generic{"modelType":"c2pa.types.model"}; the specific IPTCtrainedAlgorithmicMediasource-type is not yet present (same open item tracked on the C2PA page). This page makes no claim about that marker. - The resolver reports the authorization decision recorded at the pre-synthesis check and the current licence state. It is an attestation about authorization and licence scope — not a judgement about the audio's content beyond that.
- The values on this page come from a real production round-trip captured 2026‑09‑10. When the flow or its outputs change, this page is re-verified and updated to match; it is maintained as a factual record.
Companion to the C2PA Provenance transparency page. Permission→provenance binding: authorize → mark → the manifest carries pseudonymous references → the public resolver confirms authorization → the file stays trust-validated. Every claim here is reproducible against the live endpoint above.