Skip to content

POST /v1/verify

POST /v1/verify and GET /v1/verify/{manifest_id}

Verify an asset’s provenance. Runs multi-signal verification: C2PA manifest parse and signature check, OCSP check, watermark decode, soft-binding lookup, and anchor batch check.

The public verify endpoint (POST /v1/verify without authentication) is rate-limited per IP. Authenticated requests use per-tenant rate limits.

POST /v1/verify

POST https://api.verbitas.io/v1/verify
Authorization: Bearer vb_live_... (optional for public verify)
Content-Type: multipart/form-data (when uploading a file)
-- or --
Content-Type: application/json (when using asset_id or manifest_uri)

Request: file upload

Terminal window
curl -X POST https://api.verbitas.io/v1/verify \
-H "Authorization: Bearer $VERBITAS_API_KEY" \

Request: by asset ID

Terminal window
curl -X POST https://api.verbitas.io/v1/verify \
-H "Authorization: Bearer $VERBITAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"asset_id": "a_01j..."}'

Request: by manifest URI

Terminal window
curl -X POST https://api.verbitas.io/v1/verify \
-H "Authorization: Bearer $VERBITAS_API_KEY" \
-H "Content-Type: application/json" \
-d '{"manifest_uri": "https://m.verbitas.io/manifests/a_01j.../manifest.c2pa"}'

GET /v1/verify/{manifest_id}

Retrieve a previously-computed verification result by manifest ID (cached for the TTL of the manifest).

Terminal window
curl -H "Authorization: Bearer $VERBITAS_API_KEY" \
https://api.verbitas.io/v1/verify/a_01j... | jq .

Response: 200 OK

{
"status": "verified_manifest_and_watermark_match",
"confidence": 0.97,
"signals": {
"c2pa_manifest_present": true,
"c2pa_signature_valid": true,
"signer_trusted": true,
"timestamp_valid": true,
"ocsp_status": "good",
"watermark_present": true,
"watermark_payload_valid": true,
"fingerprint_match": false,
"anchor_match": true
},
"claims": {
"origin": "acme-pipeline.example",
"generator": "stable-diffusion-xl",
"model": "sdxl-1.0",
"ai_generated": true,
"ai_assisted": false,
"created_at": "2026-05-09T08:32:00Z"
},
"matches": [],
"warnings": [],
"developer_explanation": "C2PA manifest verified. Signer cert valid and OCSP good. TrustMark decoded; watermark_id matches manifest record.",
"user_explanation": "Provenance verified — manifest intact and watermark agrees.",
"proves": [
"The C2PA manifest was signed by a certificate on the Verbitas trust list.",
"The manifest has not been modified since signing.",
"The embedded watermark ID matches the manifest record."
],
"does_not_prove": [
"The assertions in the manifest were accurate when submitted.",
"The content is semantically truthful."
]
}

Response fields

FieldTypeDescription
statusstringOne of 16 closed-enum codes. See Verification States.
confidencefloat or null0.0-1.0 weighted signal aggregate. null for hard-failure states.
signalsobjectPer-signal boolean or string results
claimsobjectAssertions from the manifest (if present)
matchesarraySoft-binding matches (for watermark_only or fingerprint_match_only)
warningsarrayNon-fatal issues (e.g. ocsp_unavailable in dev)
developer_explanationstringTechnical summary for logging and debugging
user_explanationstringPlain-language summary for UI display
provesarraySpecific claims supported by the evidence
does_not_provearrayExplicit list of claims not supported

Tampered response example

{
"status": "manifest_tampered",
"confidence": null,
"signals": {
"c2pa_manifest_present": true,
"c2pa_signature_valid": false
},
"developer_explanation": "Claim digest mismatch: stored digest does not match computed digest of submitted asset.",
"user_explanation": "Manifest contents were altered after signing.",
"proves": [],
"does_not_prove": ["The manifest cannot be trusted — it was modified after signing."]
}

Python SDK example

import verbitas
client = verbitas.Client()
result = client.verify("received_image.jpg")
print(result.status, result.confidence)
result = client.verify(asset_id="a_01j...")
if result.status == "verified_manifest_and_watermark_match":
pass # proceed
elif result.status == "manifest_tampered":
raise ValueError(f"Asset tampered: {result.developer_explanation}")

TypeScript SDK example

import { VerbitasClient } from "@verbitas/sdk";
const client = new VerbitasClient();
const result = await client.verify({ assetId: "a_01j..." });
console.log(result.status); // "verified_manifest_and_watermark_match"
console.log(result.confidence); // 0.97

Error codes

HTTPCodeMeaning
400verbitas.verify.no_inputNo file, asset_id, or manifest_uri provided
401verbitas.auth.invalid_keyAPI key invalid (authenticated endpoint)
415verbitas.verify.unsupported_file_typeFile format not in supported set
429verbitas.ratelimit.exceededRate limit exceeded

Public endpoint

POST /v1/verify without an Authorization header is publicly accessible. The public endpoint is rate-limited to 10 requests/minute per IP and logs no PII about the requester.