Skip to content

Verify pages and the embed

llms.txtAsk agent

A verify page lets anyone, without an account or a key, check a file against your records. It reads the file’s C2PA manifest (Content Credentials) and answers one question: was this made with your system? You get one page per account, served in two ways:

  • Hosted: https://originalpictures.com/verify/{slug}/, with your name, logo and colours.
  • Embedded: the <op-verify> web component, on any page of your own site.

Both call the same public check API, described below, so you can also build your own interface.

A check states the declared origin of a file and nothing more:

  • content_credentials.status is valid, valid_untrusted, invalid or absent. valid_untrusted means the manifest is intact but its trust was not established: the signer is not on the trust list, or a trust input such as revocation status was unavailable. A file whose manifest was read is never reported absent.
  • content_credentials.declared_origin quotes what the manifest declares: signed_by, claim_generator, signed_at, ai_generated, digital_source_type, software_agent and actions.
  • made_with.answer is yes or no_record, with made_with.method (c2pa_manifest, watermark or fingerprint) when it is yes.
  • statement is a sentence every interface must show with every result:

This describes what the file declares about its origin and whether this provider’s system has a record of it. It is not a judgement of whether the content is real.

A check never says that content is real, fake, authentic or genuine, and it does not detect manipulation. A valid manifest shows who signed it and that it has not changed since; it does not show that the content is true.

made_with.answer is yes when the file’s active manifest was signed by Original Pictures for a job of your account. If you turn on recover_own_assets, it is also yes when watermark or fingerprint recovery matches one of your own assets, which can find a copy whose manifest was removed. Recovery searches only your account’s assets, never anyone else’s. In every other case the answer is no_record.

PUT /v1/verify-pages (scope verify_pages:write) creates or replaces it. Send expected_version: 0 the first time, then the version you last read:

Terminal window
curl -sS -X PUT "$OP_API_BASE_URL/v1/verify-pages" \
-H "Authorization: Bearer $OP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"slug": "studio-nova",
"display_name": "Studio Nova",
"logo_asset_id": null,
"colours": { "accent": "#cfa274", "background": "#071520", "text": "#f5f9fc" },
"recover_own_assets": true,
"enabled": true,
"monthly_check_limit": 2000,
"expected_version": 0
}'
Field Notes
slug 3 to 48 lower-case letters, digits and hyphens, not starting or ending with a hyphen. Unique.
display_name Up to 80 characters. Shown as the provider name (“made with Studio Nova’s system”).
logo_asset_id An uploaded PNG, JPEG or WebP asset (ast_…) of your account, at most 1 MB, or null. It becomes publicly readable through the page’s logo URL.
colours accent, background and text as #rrggbb; omitted ones use the defaults.
recover_own_assets true also runs watermark and fingerprint recovery against your own assets. Default false.
enabled false takes the page offline (it answers 404 publicly) and keeps the slug reserved.
monthly_check_limit The most public checks the page answers per calendar month (UTC), 1 to 100,000, or null for the platform default (10,000). Omit it to keep the current value.
expected_version 0 to create; the current version to replace. A stale version is 409.

The response includes hosted_url, the monthly_check_limit you set (null for the default) and check_usage: this month’s accepted checks against the cap in force, with period_start and period_end (when the count resets). Read the page back with GET /v1/verify-pages (verify_pages:read), which answers 404 VERIFY_PAGE_NOT_FOUND until it is saved. A taken or reserved slug is 409 VERIFY_PAGE_CONFLICT. The console’s Verify pages screen does the same with a preview and the embed code to copy.

Load the element once, then add it where the check should appear, with your page’s slug:

<script
src="https://cdn.jsdelivr.net/npm/@originalpictures/verify@0.1.0/dist/verify.iife.js"
defer
></script>
<op-verify page="studio-nova"></op-verify>

With a bundler, import "@originalpictures/verify"; defines the element, and import { verify } from "@originalpictures/verify/core"; gives the same check as a function (await verify(file, { page: "studio-nova" })). The element also takes api-base and theme (light or dark). Install it with npm i @originalpictures/verify (0.1.0 on npm since 2026-11-10), or load the script URL above. It has no dependencies, renders in its own shadow DOM, follows the visitor’s light or dark preference, and is keyboard and screen-reader accessible. A visitor drops or chooses a file, and the element shows the Content Credentials card, the “made with” answer and the statement. The file goes only to the public check API.

To let visitors inspect an image, video or audio file your page already shows, give the element the asset instead of a drop zone, with for (the id of an <img>, <video> or <audio>, whose currentSrc it reads) or src (the asset’s URL). An MP4 video is refused in the browser, before anything is sent, while public checks do not run MP4 (see media types):

<img id="hero" src="https://cdn.example.com/sunrise.jpg" alt="Sunrise" />
<op-verify page="studio-nova" for="hero"></op-verify>

The element then shows a compact button, “Check Content Credentials”. Pressing it loads the asset in the visitor’s browser, runs the same public check and labels the button “Content Credentials”, “No Content Credentials found” or “Content Credentials that do not validate”. The button expands into the same card, statement included, and collapses on the next press; pressing it again does not run a second check.

Attribute Meaning
src The URL of the asset to inspect.
for The id of a media element on the same page (or in the same shadow root).
autocheck Check when the element loads rather than on the first press. Billed every view.
  • Billing: each check is billed to you as one verification, so the element never checks on page view by default. It checks on the first press, or on load only with autocheck.
  • CORS: the browser fetches the asset, so the asset’s server must allow your page’s origin. If it does not, if the network fails, or if the asset is over 25 MB, nothing is checked: the element says so and offers the file drop instead. These failures (op-verify-error with a SOURCE_* code) happen before any check request and are not billed.
  • Function: inspect(src, { page }) from @originalpictures/verify/core does the same without the element.

These operations need no key and accept requests from any origin.

Operation What it does
GET /v1/public/verify-pages/{slug} The page’s name, logo URL, colours and limits.
POST /v1/public/verify-pages/{slug}/checks Check one file (multipart field file).
GET /v1/public/verify-pages/{slug}/checks/{check_id} Poll a check that is still running.
Terminal window
curl -sS -X POST "$OP_API_BASE_URL/v1/public/verify-pages/studio-nova/checks" \
-F "file=@photo.jpg"

The answer is 200 with a completed check, or 202 with state: "running" and a check_id (pchk_…) for a file that takes longer, such as a large audio file. Poll at most every 2 seconds; a check expires 15 minutes after it was created.

  • Size: at most 25 MB. A larger file is 413 MEDIA_COMPRESSED_SIZE_LIMIT.
  • Media types: GET /v1/public/verify-pages/{slug} lists what a check accepts in accepted_media_types (JPEG, PNG, WebP, TIFF, AVIF, WAV, M4A, MP3, FLAC and PDF where the deployment admits them). MP4 video is not checked on a public page today: it is refused with 415 PUBLIC_CHECK_MEDIA_UNSUPPORTED, whose message lists the accepted types, before anything is staged or billed. A file whose format cannot be read is 422 MEDIA_FORMAT_UNDETECTED. To verify a video you signed, use POST /v1/verifications on the stored object.
  • Rate limit: 10 checks a minute and 100 a day per network and page, and 120 a minute and 2,000 a day per page across all networks. Over a limit is 429 PUBLIC_CHECK_RATE_LIMITED with Retry-After.
  • Monthly cap: past the page’s monthly_check_limit (or the default 10,000) in a calendar month, checks are 429 PUBLIC_CHECK_MONTHLY_LIMIT_REACHED with Retry-After until the next month starts (UTC). The cap counts accepted, billed checks.
  • Privacy: the file is held only for the check. It is never stored with the result and never logged, and neither are its file name and the visitor’s IP address (the rate limit uses a keyed hash of it).
  • Billing: each public check is billed to you, the page owner, as one verification; see Retention and pricing.

To check many of your own stored outputs at once, use POST /v1/verifications/batch instead: up to 100 object_ids in one call, each exactly as POST /v1/verifications would accept it.