Verify
Verification checks an immutable stored object and records evidence you can read, report on, and share. It is asynchronous.
Create a verification
Section titled “Create a verification”POST /v1/verifications takes the immutable object
identifier (aob_…) returned when an upload completes. It also requires an Idempotency-Key
header.
curl -sS -X POST "$OP_API_BASE_URL/v1/verifications" \ -H "Authorization: Bearer $OP_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d "{\"object_id\": \"$ASSET_OBJECT_ID\"}"The parent asset ID (ast_…) cannot stand in for an object ID. Unknown request fields are
rejected.
The 202 response is a snapshot with a pollable verification_id (vjob_…) and state.
Verify a pair another product signed
Section titled “Verify a pair another product signed”Some formats carry their C2PA manifest in a separate .c2pa file instead of inside the asset.
These include documents, fonts, ML models, and the container-family types. For a pair this
service signed, send only object_id, and the stored manifest is found for you. For a pair
another product signed:
- Upload the asset with its own media type, and upload the
.c2pafile withdeclared_media_typeset toapplication/c2pa(8 MiB at most). - Send both object identifiers:
curl -sS -X POST "$OP_API_BASE_URL/v1/verifications" \ -H "Authorization: Bearer $OP_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d "{\"object_id\": \"$ASSET_OBJECT_ID\", \"manifest_object_id\": \"$MANIFEST_OBJECT_ID\"}"- A format that carries its manifest inside the file is refused with
422VERIFY_MANIFEST_NOT_APPLICABLE. Sendobject_idalone. - A manifest object that is not an
application/c2paupload within the size limit, or is the asset itself, is refused with422VERIFY_MANIFEST_INVALID. - A manifest object you do not own is reported as
404VERIFY_NOT_FOUND, exactly as an unknown one is. - Bytes that are not a C2PA manifest store, or an asset that does not match the manifest’s
hard binding, are validation results, not request errors. The verification completes with
status
invalid_tampered, and the C2PA status codes are in the evidence.
If a document or other sidecar-type asset carries a manifest inside the file, send
object_id alone and the embedded manifest is read. Some embedded forms cannot be read yet. For
those the result is unavailable with VALIDATION_MANIFEST_UNSUPPORTED, which makes no claim
about the manifest.
Verify never fetches a remote manifest. If a manifest is published at a remote reference,
download it yourself and upload it as application/c2pa.
Poll the verification
Section titled “Poll the verification”Poll GET /v1/verifications/{verification_id} until
state is completed or failed. The polling rules are in
Asynchronous contracts.
completed:result,evidence_id(vfy_…), andcompleted_atare present.failed:failure_reason(a reason code) andcompleted_atare present.
A vjob_… identifier is only a job handle and must never be stored as evidence. Evidence IDs
start with vfy_.
Direct validation and recovery
Section titled “Direct validation and recovery”Verification first validates the object’s C2PA manifest directly. If direct validation does not establish validity, a bounded recovery may search watermark and fingerprint bindings for a single matching candidate.
- No manifest could be read and recovery finds one candidate: the result is marked
recovery-only (reason
VALIDATION_RECOVERY_ONLY). That is not cryptographic validity: show it as recovered provenance and keep the reasons and recovery evidence that come with it. - A manifest was read: its finding is the status (
invalid_tampered,revoked,expired,untrusted, orunavailable), and a recovery match is reported beside it inresult.recoveryas supplementary evidence. It never upgrades or replaces that status.
Results with schema_version op.public-verify-result.v2 also carry:
result.manifest: a bounded summary of what the active manifest declares (claim generator, signer common name, issuer, algorithm and serial, trusted signing time, actions, assertion labels, soft bindings, ingredients, manifest count and the validation status codes). It isnullwhen no manifest was read. It describes the manifest; it is not the verdict.result.recovery.signals: which watermark or fingerprint signal recovery evaluated, its algorithm, and the score or distance measured. It never names the matched asset.
Earlier results (op.public-verify-result.v1) are stored evidence and are returned exactly as
issued, without these fields. See Lookup and recovery.
Evidence, reports, and shares
Section titled “Evidence, reports, and shares”GET /v1/verification-evidence/{verification_id}reads the full evidence for avfy_…ID.POST /v1/verification-evidence/{verification_id}/reportsgenerates a report from the evidence. Download it withGET /v1/verification-reports/{report_id}.POST /v1/verification-evidence/{verification_id}/sharesissues an expiring, revocable share link.GET /v1/shared-verifications/{token}returns only the minimal projection that share allows.
What verification does not prove
Section titled “What verification does not prove”A valid result shows that a manifest was signed by a trusted certificate and matches the bytes you submitted. It does not show that the claims in the manifest were accurate when they were made, or that the content is truthful.
