One API for C2PA validation. Billed once per report.
Send JPEG, PNG, WebP, MP3, WAV, M4A or MP4 to one authenticated endpoint and receive the hosted validator’s complete structured report, with its Evidence Unit charge in the same response. Every report identifies the exact validator build. Idempotency keys make retries safe: one key is never charged twice.
API access is included for developers · seven hosted formats · 2 Evidence Units per completed report
From first file to production.
1. Verify a file free
Check a file in the browser, with no account. Free Verify checks JPG and PNG photos up to 1 MB for Content Credentials; it reports present — not evaluated, none detected, or not checked. Exact ChaosMark record matches are reported separately. Full validation is a separate, paid hosted evaluation.
2. Subscribe and upload
When online subscription is enabled, secure Stripe Checkout returns you to an account that accepts all seven formats in the browser. The account handles authentication, reports, usage and recovery without exposing an API key.
3. Automate from your server
Developers may reveal a separate API key once from the paid account. One HTTP call per file sends raw bytes in and returns the report, Evidence Units and billing state.
Customers can validate without an API key.
A paid account includes drag-and-drop browser upload, the full findings, recent validation history, retained-report retrieval and subscription management. The browser session is bound to the account on the server; it never copies an API key into HTML, JavaScript, a cookie or a URL.
The API remains available
Server integrations use the same validator, Evidence Unit ledger, idempotency rules and report custody through POST /v1/c2pa/validate. Browser and API requests do not create separate billing or validation systems.
For software and AI agents
People subscribe through secure Stripe Checkout and upload files in the browser. Authorized software and AI agents use the API with a key issued to an accountable person or organization.
Who holds the account
A person or organization chooses the plan, accepts the Terms and pays through Stripe Checkout. They reveal the API key from their paid account and give it to the agent or automation they authorize, and they stay responsible for how it is used.
What an agent can do
Send a file to POST /v1/c2pa/validate, retry safely with the same idempotency key, and look up a report and its usage for up to 24 hours. Every call uses the same seven formats, limits and report as the browser.
Built-in limits
Each completed report uses 2 Evidence Units. When the plan's allowance or request limits are reached, requests are refused at 0 Evidence Units. There is no overage, so an agent cannot spend beyond the plan.
A plain-text summary for automated readers is at /llms.txt. Looking for something other than a monthly plan? Explore other options.
API reference
POST /v1/c2pa/validate. Raw body, not multipart. The bytes decide the format; the declared type must agree with them.
curl "$CHAOSMARK_API_BASE/v1/c2pa/validate" \
-H "Authorization: Bearer $CHAOSMARK_API_KEY" \
-H "Content-Type: image/jpeg" \
-H "Idempotency-Key: photo-2026-09-29-0001" \
--data-binary @photo.jpg
Request
Authorization: Bearer <key>Content-Type:image/jpeg,image/png,image/webp,audio/mpeg,audio/wav,audio/mp4orvideo/mp4Idempotency-Key: required, 1–128 characters, letters, digits and. _ : -, starting with a letter or digit- Body: the file's bytes. PNG up to 1 MiB; the other hosted formats up to 16 MiB; uploaded within 30 seconds
Completed response (200)
status:completed, andreport: the validator's full reportcharged_eu: 2,billing_state:finalizedreservation_idandusage_event_id: the purchase and its usage record, for retrieval laterrequest_commitmentandresult_commitment: digests you can keep and check laterinput_sha256: the digest of the bytes you sent; the bytes themselves are not kepttrust_material: digests of the trust lists the report was evaluated againsthosted_api_mediaandc2pa_validator_media: this endpoint's formats and the validator's, never mixed upresult_identity: the validator build that produced the report. For the hosted successor build,build_record.cpl_record_idisnullandbuild_record.conformance_mappingisnot-established: that build is not itself currently listed
Your API base URL is issued with your key. A completed report is billed whatever it finds, including invalid or untrusted credentials: you pay for the evaluation, not for a favourable answer. Refused input, unreadable containers and timeouts cost 0 Evidence Units, and the response says so in charged_eu and billing_state. If a failure on our side leaves the charge undetermined, billing_state says so until it is settled; check the final state by reservation_id.
Retries that never bill twice.
An idempotency key is bound to one request: the same key with the same bytes is the same request. Retry with the same key. A new key is new billable work, except that a new key for bytes already being bought under your organization is refused at 0 Evidence Units, and so is one for bytes bought recently unless you confirm a repeat purchase.
| Answer | Status | What it means | What to do |
|---|---|---|---|
| No response | Network error or timeout | You cannot tell whether the request ran. | Retry with the same key. |
| Still running | 409 in_flight | This key is still being evaluated. | Wait, then retry with the same key. |
| Busy | 429 validation-capacity-exhausted, 503 validation-service-unavailable, 503 validation-report-custody-unavailable | Busy or unavailable. Nothing was charged. | Back off, then retry with the same key. |
| Recovered | 200 with replayed: true | This key already completed and was charged once. You get the same report again: nothing ran again and nothing more was charged. | Nothing: this is your original result. |
| Recovery paused | 503 validation-report-recovery-unavailable | Charged once already; the kept report could not be read just now. | Retry with the same key. It never charges again. |
| Already done | 410 validation-report-expired, or 409 already_finalized when the report's state cannot be classified | This key completed and was charged once, and its report is no longer kept (the keeping period has ended). | Do not retry. The request_commitment matches your first response. A new key is a new, separately charged request. |
| Not kept | 503 validation-report-not-retained | The validation ran, but its report could not be kept, so it was not sold: nothing was charged and nothing will be. This key is closed. | Send a new key to try again. |
| Released | 409 already_released | An earlier request with this key ended without a charge. | Send a new key if you want a new evaluation. |
| Same bytes, open | 409 purchase_in_progress | These bytes are already being bought under another key in your organization. Nothing was charged and nothing ran. Confirming a repeat purchase does not apply while it is open. | Wait, and retry with that key. If the earlier purchase is your account's, prior_reservation_id names it; otherwise it is null. |
| Same bytes, recent | 409 repeat_purchase_requires_confirmation | These bytes were bought under another key and that report can still be retrieved. Nothing was charged. | Retrieve the earlier report (by prior_reservation_id when it is your account's), or send ChaosMark-Repeat-Purchase: confirm to confirm a repeat purchase. |
| Key conflict | 409 idempotency_conflict | This key was already used for different bytes. | Use a new key for a different file. |
| Undetermined | 409 reconciliation_required, 503 validation-settlement-unconfirmed | Billing is undetermined; a person reconciles it. | Do not retry. Contact us with the reservation_id. |
| Budget used | 429 attempt-budget-exhausted | Your request budget is used up. | Do not retry until your budget resets. |
| Day used | 429 daily-attempt-budget-exhausted, 429 daily-evidence-unit-budget-exhausted | Your organization has used this UTC day's request or Evidence Unit budget. Nothing was charged. Each finished report that is still kept can be read once more after a request-budget refusal. | Wait for the time in Retry-After, the next UTC midnight, then retry with the same key. |
Look up a paid validation.
By the reservation_id on the response, or by your idempotency key if the response was lost. Lookups read only: they cost 0 Evidence Units and run nothing. Each lookup still counts as one request toward your plan's request limits.
GET /v1/c2pa/validations/{reservation_id}
or GET /v1/c2pa/validations/by-idempotency-key/{idempotency_key}
- Billing state, and
charged_euonly once the charge is confirmed - Both commitments, and the report while it is kept
report_status:available,expired,not_retained,not_applicable, orintegrity_failure(charged; ChaosMark reconciles it)
GET /v1/usage/reservations/{reservation_id}
- The usage record: period,
usage_event_id, quoted and confirmed Evidence Units - Reservation state, reason code and reconciliation status
- Usage comes from ChaosMark's own ledger; your invoice covers the plan period, not each validation
A paid report is available for recovery for up to 24 hours after the charge, so a lost response can still be retrieved; after that, the billing record and the commitments remain. The file you send is not kept. An unknown reservation and another account's get the same 404.
Errors
Every refusal has a status and a fixed reason string, and says whether anything was charged.
| HTTP | Reasons | Charged |
|---|---|---|
| 400 | content-type-required, content-length-malformed, idempotency-key-required, idempotency-key-malformed, asset-empty | 0 Evidence Units |
| 401 | credential-not-accepted | 0 Evidence Units |
| 404 | reservation-not-found (lookups only) | 0 Evidence Units |
| 402 | no-active-contract, insufficient-evidence-units, operation-not-entitled, outside-contract-period, payment-not-authorized | 0 Evidence Units |
| 408 | asset-upload-too-slow | 0 Evidence Units |
| 413 | content-length-exceeds-limit, asset-exceeds-limit | 0 Evidence Units |
| 415 | content-type-not-supported-by-hosted-api, asset-media-outside-hosted-api-scope (a validator format this endpoint does not accept yet), asset-media-not-recognised, asset-media-disagrees-with-declared-type, asset-media-disagrees-with-filename, asset-media-ambiguous (the bytes read as more than one format) | 0 Evidence Units |
| 422 | asset-container-unreadable, asset-exceeds-validator-bound (the file holds a Manifest Store larger than the validator’s resource limits; never reported as “no manifest”), remote-manifest-not-retrieved (the file points to a remote manifest, which is not fetched), asset-media-outside-hosted-api-scope (an MP4 or M4A whose hash binding is a Merkle tree, which this endpoint does not evaluate), validation-report-exceeds-limit | 0 Evidence Units |
| 429 | attempt-budget-exhausted, daily-attempt-budget-exhausted, daily-evidence-unit-budget-exhausted, validation-capacity-exhausted, credential-lookups-rate-limited | 0 Evidence Units |
| 500, 504 | validation-failed, validation-timed-out | 0 Evidence Units, when billing_state is not_billable |
| 503 | validation-service-unavailable, validation-paid-route-stopped, validation-paid-schema-unavailable, validation-cost-envelope-exceeded, validation-capacity-lease-lost, validation-report-custody-unavailable, validation-report-not-retained | 0 Evidence Units |
| 503 | validation-worker-unsettled, validation-settlement-unconfirmed | 0 Evidence Units when billing_state is not_billable; otherwise undetermined until a person reconciles it |
The 409, 410 and recovery answers are in the retry table above. A request beyond your plan's allowance is refused, never billed as overage. Formats: what each format supports today.
Your account, key and plan.
How browser access and developer access start, what limits apply, and what happens at the end of each monthly period.
Getting access
You agree to the Terms of Service and Privacy Policy and pay for the first monthly period. A signed paid-invoice confirmation activates browser validation. The account can create a separate recovery code for restoring browser access after its session expires.
Developers may reveal the first API key once from the account. It is shown once; ChaosMark keeps only a digest of it and cannot show it again. Browser customers never need to reveal or use the key.
Keeping it secret
Keys begin with cmk_k_. Send the key only in the Authorization: Bearer header, from your server. Never put it in browser or mobile app code. A missing, unknown or revoked key gets the same 401 credential-not-accepted, and costs 0 Evidence Units.
If a developer key is lost, email us (never the key itself): a person revokes it and issues a new one. Browser access continues without it.
Limits
Each plan has a number of validations that can run at once and a number of requests per clock minute; every plan has a daily request limit, and catalog-only Scale also has a daily Evidence Unit limit. Compare the limits. Each authenticated validation request and each lookup counts. A refused request is answered 429 and costs 0 Evidence Units; the retry table above says when to try again.
Each monthly period
Each paid period starts with its plan's Evidence Units. Unused Evidence Units do not carry over, and no overage is billed: once the allowance is used, validations are refused with 402 insufficient-evidence-units until the next period.
Renewal and ending a plan
A renewed plan keeps the same browser account and developer key. If a period ends before the next one is paid, new validations are refused with 402 outside-contract-period and nothing is charged. Earlier retained reports remain available under their retention rules. Request cancellation from the paid account; service continues through the period already paid for unless it is suspended under the Terms. For a sales-assisted plan, email us.
Refunds and disputes
If a payment is not authorized, fully refunded, or a dispute is lost, we may suspend the plan. While it is suspended, validations are refused with 402 payment-not-authorized, or 401 if the key is revoked, and cost 0 Evidence Units.
Clients and integrations
Python and TypeScript clients
Thin clients over this endpoint are next: key configuration, idempotency keys, typed results and errors, the retry rules above, recovery of a lost response with the same key, and the two lookups. No SDK package is published yet, and there is no self-service key-issuance endpoint; until the clients ship, any HTTP client works, as in the example.
Agent Evidence
Evidence of what an agent was authorized to do and what the destination shows it did, from MCP, OpenTelemetry / OTLP, A2A and compatible HTTP sources.
Recognition
Whether a JPEG or PNG stripped of its credentials is still exactly a file you registered, by its bytes or by its decoded pixels.
Public resources
Published verification keys
The public keys ChaosMark records are signed with, for checking a record with standard tooling.
Result vocabulary
Every result Verify can return, and what each one does and does not mean.
Labelled sample result
A worked example of a result, so you know what to expect before integrating.
C2PA Conformant Validator Product
The listed product’s recorded scope is JPEG, PNG, WebP, MP4, MP3, WAV and M4A under C2PA Specification 2.2. Hosted reports name their exact build so reviewers can check the applicable product and build details.
Local Agent for Windows
ChaosMark Local Agent 0.2.2 is available for Windows 11 x64. It protects and verifies files on your own computer; it is a desktop application, not a developer library.
Technical evaluation
Agree the evidence you need, the keys you trust, what data may leave your systems, and how success is tested.
Treat each signature, each file fingerprint, each key or certificate you supplied, and any missing evidence as a separate finding. Do not infer truth, identity, authorization, correctness, or completeness. Read the trust boundary.