Quick start
1Get an API key
Sign in, open your dashboard and create a key under API keys. The full key is shown once.
2Mark an image
curl -X POST https://engine.proofcan.com/v1/mark \ -H "Authorization: Bearer $PROOFCAN_API_KEY" \ -F "file=@image.png" \ -o image-marked.png3Verify it
curl -X POST https://engine.proofcan.com/v1/verify \ -H "Authorization: Bearer $PROOFCAN_API_KEY" \ -F "file=@image-marked.png"
The Proofcan API marks images from your own servers with the same signing path as the web app: a C2PA manifest that declares the image AI-generated, an invisible TrustMark watermark carrying the record's lookup ID, and an entry in the Proofcan registry. Base URL: https://engine.proofcan.com. Machine-readable description: /v1/openapi.json (OpenAPI 3.1).
Authentication
Create a key in your dashboard under API keys. The full key is shown once, when you create it; Proofcan stores only its SHA-256 hash and the first characters for display. Send it in every request:
Authorization: Bearer pc_live_…An account can have up to 5 active keys. Revoking a key takes effect on the next request. Keep keys on your servers: the API does not send CORS headers, so it cannot be called from a browser page.
POST /v1/mark
Multipart form. file: a JPEG, PNG or WebP image (the type is read from the file's signature, not its name), at most 50 MB and 50 megapixels. Optional text fields, up to 100 characters each: ai_system_name, ai_system_version (only together with a name), provider_name. When given, they are written into the Proofcan assertion (org.proofkit.marking) of the signed manifest as ai_system and provider.
The response body is the marked file, in the format you uploaded. Headers:
Proofcan-Lookup-Id: the 8-character ID in the watermark and the registry.Proofcan-Record-Url: the public record page.Proofcan-Quota-Remaining: marks left in the current period, after this one.Proofcan-Sha256: SHA-256 of the returned file.
The marked file also appears in your dashboard and can be downloaded there for 24 hours.
POST /v1/verify
Multipart form with file. Returns whether the image carries a C2PA manifest and whether its signature is valid, whether the watermark was found, the lookup ID, the registry record and whether the file is byte-identical to the one that was registered. Does not use quota.
Response
{ "c2pa": { "present": true, "valid": true, "state": "Valid", "ai_declared": true }, "watermark": { "found": true, "lookup_id": "ABCDEFGH" }, "lookup_id": "ABCDEFGH", "record": { "lookup_id": "ABCDEFGH", "registered_at": "2026-10-30T12:00:00Z", "sha256": "…", "claim_generator": "Proofcan/0.2.0", "digital_source_type": "http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia", "watermark": "TrustMark Q/BCH_4", "record_url": "https://www.proofcan.com/verify?id=ABCDEFGH" }, "sha256_match": true}GET /v1/records/{lookup_id}
The public registry record for a lookup ID (8 characters, A–Z and 2–7): registration time, SHA-256, claim generator, digital source type, watermark. No personal data.
GET /v1/usage
plan, used, limit, remaining, period_start and renews_at for the current quota period.
Examples
curl -X POST https://engine.proofcan.com/v1/mark \ -H "Authorization: Bearer $PROOFCAN_API_KEY" \ -F "file=@image.png" \ -F "ai_system_name=Example Image Model" \ -F "ai_system_version=2.1" \ -F "provider_name=Example AI Ltd" \ -D headers.txt -o image-marked.png# Verify a file (does not use quota)curl -X POST https://engine.proofcan.com/v1/verify \ -H "Authorization: Bearer $PROOFCAN_API_KEY" \ -F "file=@image-marked.png"# Registry record by lookup IDcurl https://engine.proofcan.com/v1/records/ABCDEFGH \ -H "Authorization: Bearer $PROOFCAN_API_KEY"# Plan and usagecurl https://engine.proofcan.com/v1/usage \ -H "Authorization: Bearer $PROOFCAN_API_KEY"Errors
Every error has the same JSON shape:
{ "error": { "code": "quota_exceeded", "message": "Monthly quota used up (100/100). Upgrade your plan or wait for the next period." }}| Status | Meaning |
|---|---|
| 400 | Malformed request, missing or empty file, corrupt image, unknown or too long field. |
| 401 | Missing, invalid or revoked API key. |
| 402 | The monthly quota is used up (quota_exceeded). |
| 404 | No record with this lookup ID, or unknown path. |
| 413 | File larger than 50 MB or image larger than 50 megapixels. |
| 415 | Not a JPEG, PNG or WebP image. |
| 429 | Rate limit or concurrency limit reached. Wait the number of seconds in Retry-After. |
| 5xx | Server error. 503 means busy or temporarily unavailable and carries Retry-After. A failed mark does not use quota. |
Limits
/v1/mark: 30 requests per minute per key, and at most 2 running at the same time per key./v1/verify: 60 requests per minute per key./v1/recordsand/v1/usage: 60 requests per minute per key, together.- Per client address: 240 requests per minute; after 20 failed authentications in 10 minutes, further requests get 429 for the rest of that window.
- Files: JPEG, PNG, WebP; 50 MB; 50 megapixels.
Quota
API marks use the same monthly quota as marks made in the web app; see pricing. A mark counts only when it succeeds: if the request fails after the quota check (invalid file, server error), the reserved mark is returned. On the Free plan the quota renews on the first day of each month (UTC); on paid plans at the end of the billing period. Verify, records and usage do not use quota.
Support
Questions and problem reports: support@proofcan.com. Security reports: /security.