Skip to content

Verify

llms.txtAsk agent

Verification checks an immutable stored object and records evidence you can read, report on, and share. It is asynchronous.

POST /v1/verifications takes the immutable object identifier (aob_…) returned when an upload completes. It also requires an Idempotency-Key header.

Terminal window
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.

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:

  1. Upload the asset with its own media type, and upload the .c2pa file with declared_media_type set to application/c2pa (8 MiB at most).
  2. Send both object identifiers:
Terminal window
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 422 VERIFY_MANIFEST_NOT_APPLICABLE. Send object_id alone.
  • A manifest object that is not an application/c2pa upload within the size limit, or is the asset itself, is refused with 422 VERIFY_MANIFEST_INVALID.
  • A manifest object you do not own is reported as 404 VERIFY_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 GET /v1/verifications/{verification_id} until state is completed or failed. The polling rules are in Asynchronous contracts.

  • completed: result, evidence_id (vfy_…), and completed_at are present.
  • failed: failure_reason (a reason code) and completed_at are present.

A vjob_… identifier is only a job handle and must never be stored as evidence. Evidence IDs start with vfy_.

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, or unavailable), and a recovery match is reported beside it in result.recovery as 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 is null when 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.

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.