Public Verification API

Verify the content authenticity of any file—C2PA Content Credentials and embedded standards metadata. Unauthenticated, stable, and free.

POST
/api/v1/public/verify

Official versioned endpoint. Send a multipart file field. The unversioned /api/verify is a stable back-compat alias.

Public

Request

# Verify any file — public, no account or key required
curl -X POST https://api.krusade.dev/api/v1/public/verify \
  -F "[email protected]"

# The unversioned alias behaves identically:
curl -X POST https://api.krusade.dev/api/verify \
  -F "[email protected]"

Rate limited to 30 requests per minute per client IP. Supported inputs: JPEG, PNG, WebP, AVIF, TIFF, GIF, MP4, MOV, MP3, WAV, FLAC, and PDF (verify-only).

Response

status
"valid" | "invalid" | "no_credentials"

Overall verdict. Unsigned files return no_credentials with 200.

trusted
boolean | null

True when the certificate chain verified against a trusted root.

issuer
string

Signing certificate issuer.

assertions
Assertion[]

Labelled provenance metadata from the active manifest.

errors
string[]

Validation failure codes when status is invalid.

signer
{ subject, cert_serial }

Signing certificate identity.

signed_at
{ time, timestamped }

Claim time and whether an RFC 3161 timestamp backs it.

ingredients
Ingredient[]

Parent/component assets referenced by the manifest.

Example

{
  "status": "valid",
  "trusted": true,
  "issuer": "Krusade",
  "signed_at": { "time": "2026-07-05T00:00:00Z", "timestamped": true },
  "assertions": [
    { "label": "stds.schema-org.CreativeWork", "data": { "author": "Jane Doe" } }
  ]
}

Errors

Errors follow RFC 7807 problem+json with a machine-readable code field. An unsigned file is not an error — it returns 200 with status: "no_credentials".

415

Unsupported or undetectable media type.

413

Asset exceeds the maximum upload size (64 MB).

408

Upload read deadline exceeded.

429

Rate limit exceeded (30 requests/minute per IP).

503

Verification service temporarily unavailable.