— Developers
A report schema built to be filed as an exhibit
Score images from your own code with a bearer key and get back the same versioned JSON the web app produces. API access is included with every plan, including the free trial, and spends the quota you already have.
— API
The analysis API
Create a key on your account page and you can score images from anywhere. Calls run against two hosts: your account issues a token, and the stateless analysis host does the scoring.
AuthEvery call starts with a key you create at your account page. Keys are shown once and stored only as a hash, so a leak of our database cannot yield a working key. Revoke one at any time and it stops authenticating on the next request.
| Method | Path | |
|---|---|---|
| POST | https://vestigeforensics.com/api/v1/token | Exchange your API key for an analysis token bound to one image. Consumes one analysis from your quota. |
| POST | https://api.vestigeforensics.com/v1/analyze | Score one image with a token from the exchange; returns the forensic report. Multipart: image, fpr_cap, optional condition. |
| GET | https://vestigeforensics.com/api/v1/usage | Analyses used, your limit, when the quota resets, and your tier. Free to call. |
| DELETE | https://api.vestigeforensics.com/v1/reports/{report_id} | Acknowledges deletion. Nothing is stored server-side, so there is nothing for it to remove. |
| POST | https://api.vestigeforensics.com/v1/analyze/batchcoming soon | Several images in one request. Still in engineering, not callable yet. |
Why two hosts
Your quota and your identity live with your account. The host that actually sees your image holds no database and no user records, so it cannot store anything even in principle. Splitting the two is what lets us say images are never stored and mean it literally.
The token you get back is bound to the SHA-256 you sent, and the analysis host rejects any upload whose bytes hash differently. That binding is a privacy feature rather than a limitation: it is what makes the scoring host safe to run with no memory of who you are. One token scores one image, and it expires ten minutes after it is issued.
The report is the contract
The API returns exactly the JSON document on the right, the same report the web app generates and lets you download. Build your pipeline against the schema below.
DeletionDELETE /v1/reports/{id} acknowledges deletion for workflow symmetry, but images are analyzed in memory and removed as soon as the report is written, so there is nothing server-side for it to remove. See the privacy commitments.
{
"report_id": "VF-9E41C7A2",
"created_at": "2026-07-12T14:32:08Z",
"report_sha256": "4c8d1a96f0b3e7255d9c02aa8f16de433b7a90c1e5f2481706bd3c5a92e8f014",
"service": {
"name": "Vestige Forensics",
"pipeline_version": "2026.07.4-production",
"calibration_ref": "full_v4"
},
"image": {
"filename": "exhibit_2216-042.jpg",
"byte_size": 287644,
"mime_type": "image/jpeg",
"width": 1280,
"height": 960,
"sha256": "9e41c7a2d05b8ff31c26e94a7d10b5c8e2f6a03d914b7ce50a8d21f6b3e49c77"
},
"primary": {
"id": "cf_finetuned",
"label": "Community Forensics — VF fine-tune",
"venue": "CVPR 2025 base",
"score": 0.941
},
"supporting": [
{
"id": "community_forensics",
"label": "Community Forensics (stock)",
"venue": "CVPR 2025",
"score": 0.212
},
{
"id": "sdxl_detector",
"label": "SDXL Detector",
"venue": "Community (HF)",
"score": 0.716
}
],
"decision": {
"fpr_cap": 0.01,
"threshold": 0.7254,
"verdict": "ai_flagged_strict",
"tpr_at_cap": 0.429
},
"robustness": {
"estimated_condition": "social_chain",
"honesty_gap": 0.504,
"per_degradation": [
{
"degradation": "clean",
"tpr_at_fpr5": 0.641
},
{
"degradation": "jpeg_q70",
"tpr_at_fpr5": 0.609
},
{
"degradation": "jpeg_q50",
"tpr_at_fpr5": 0.617
},
{
"degradation": "resize_50",
"tpr_at_fpr5": 0.611
},
{
"degradation": "whatsapp",
"tpr_at_fpr5": 0.551
},
{
"degradation": "screenshot",
"tpr_at_fpr5": 0.596
},
{
"degradation": "social_chain",
"tpr_at_fpr5": 0.554,
"note": "estimated condition of this image"
}
]
},
"limits": [
"A flag is a calibrated statistical signal, not proof that an image was generated by AI. Check provenance and context before you act on it.",
"The encoding fingerprint points to screenshot-style re-encoding. Sensor-level signals cannot be recovered from an image in that state.",
"We expect the stock model to lag on 2024+ generators, and at 0.212 it does. Closing that gap is why the fine-tuned primary drives the verdict here. Supporting signals corroborate; they never decide.",
"At the strict ≤1% false-positive standard the calibrated detection rate is 43%, so the absence of a flag would have been weak evidence that the image is authentic.",
"Generators released after the calibration run may not be represented, and a score on a generator we have never seen can be arbitrarily wrong.",
"This verdict applies to the exact bytes hashed above. Re-export or edit the file and you have a different exhibit."
],
"sample": {
"simulated": true,
"note": "Sample document with representative values. The detector scores are illustrative; the thresholds and detection-power figures come from calibration run full_v4."
}
}— Quickstart
Three commands to your first report
Hash the image, trade the hash for a token, then send the image. Set VF_API_KEY to a key from your account page first.
1Hash the exact bytes you are going to upload.
sha256sum image.jpg
# 9f2c... image.jpg2Exchange your key for a token. This is the call that spends one analysis, whether or not you go on to use the token.
curl -s -X POST https://vestigeforensics.com/api/v1/token \
-H "Authorization: Bearer $VF_API_KEY" \
-H "Content-Type: application/json" \
-d '{"sha256":"9f2c..."}'
# {"token":"eyJhbGci...","expires_in":600,
# "used":7,"limit":100,"resetsAt":"...","tier":"pro"}3Send the image to the analysis host with that token.
curl -s -X POST https://api.vestigeforensics.com/v1/analyze \
-H "Authorization: Bearer $TOKEN" \
-F "image=@image.jpg" \
-F "fpr_cap=0.05"
# the full forensic report, shown on the rightLimitsUploads are capped at 15 MB and 50 megapixels. fpr_cap is 0.05 (standard) or 0.01 (strict). Short-window request limits apply per account and are higher on Vestige Pro; your monthly or weekly quota is the real ceiling, and GET /api/v1/usage tells you where you stand without spending anything.
— Errors
What can go wrong, and which host said so
Errors are returned as JSON with an error key. Failures surface as failures: a call that did not produce a real analysis never returns something that looks like one.
| Status | Host | Meaning |
|---|---|---|
| 400 | Account | sha256 missing or not a lowercase 64-character hex digest. |
| 401 | Account | API key missing, malformed, unknown, or revoked. All four answer identically. |
| 401 | Analysis | Analysis token missing, expired, or not signed by us. Tokens last ten minutes. |
| 403 | Analysis | The uploaded bytes do not hash to the sha256 the token was issued for. |
| 413 | Analysis | Image over 15 MB or over 50 megapixels. |
| 415 | Analysis | The upload could not be decoded as an image. |
| 422 | Analysis | fpr_cap was not 0.05 or 0.01, or condition was not a known value. |
| 429 | Account | Quota for the period is spent. The body carries used, limit, and resetsAt. |
| 429 | Analysis | Too many requests in a short window. Retry-After tells you how long to wait. |
A 401 from the account host is deliberately the same whether the key is unknown, revoked, or never existed. Telling the two apart would confirm to anyone probing that a given key was once real.
— Pricing
Two tiers you can actually buy
2 analyses a week, free, no card; or Vestige Pro at $2.99/month for 100. API access is included with both and spends the same quota, so there is nothing extra to buy to use it.
Free trial
Available now$02 analyses / week
Available now. Sign up, verify your email, analyze — no card, no sales call.
- 2 full forensic reports per week
- Standard (≤5% FPR) and strict (≤1% FPR) verdicts
- JSON + web report with chain-of-custody hashes
- API access included, drawing on the same weekly quota
- No human ever sees your images, and they are never stored
Vestige Pro
Available now$12$2.99per month
Limited-time launch price
Available now. Regular casework volume, same detector, same privacy stance.
- 100 full forensic reports per month
- Standard (≤5% FPR) and strict (≤1% FPR) verdicts
- JSON + web report with chain-of-custody hashes
- API access included, drawing on the same 100 a month
- No human ever sees your images, and they are never stored
- Cancel any time, with access to the end of the period
API access
Includedwith your plan
Analyze from your own code. Keys draw on the quota you already have, so there is no separate API bill.
- Bearer keys you create and revoke on your account page
- Single-image analyze plus a usage endpoint
- The same report JSON the web app returns
- Included on the free trial as well as Vestige Pro
Enterprise / Forensic
Coming soonCustomannual
For labs and legal teams with evidentiary requirements.
- Methodology pack + calibration disclosures
- Expert-report support
- Pinned pipeline versions per case
In development
- · Vestige Pro is at a limited-time launch price of $2.99/month while we grow. The regular price is $12/month.
- · The free trial and Vestige Pro are the tiers you can actually buy today. Enterprise is still in development, and its features describe intent, not a promise date.
- · API access is included with both, and it spends the same quota: an analysis costs one unit whether it came from the web app or your code.
- · Trial quota resets every Monday 00:00 UTC; Vestige Pro resets on the 1st of each month (UTC). Analyses are counted when authorized, whether or not the upload completes.
- · Payments are handled by Polar, our merchant of record. They process the payment and issue the invoice, and card details never reach our servers.
- · Cancel Vestige Pro any time from the billing portal on your account page; access continues to the end of the period you paid for.
— Report format
The forensic report, field by field
One JSON document, versioned and hashed. The response example above is rendered from the same object as this schema, so the docs cannot drift from the type.
Root
report_idstring“VF-” + first 8 hex chars of the image hash. Stable across re-analysis of identical bytes.created_atISO 8601Report creation time, UTC.report_sha256hex(64)SHA-256 of the canonical report JSON (this field excluded). Tamper-evidence for the document itself.service.pipeline_versionstringPinned pipeline release that produced this report. Cite it; reproduce with it.service.calibration_refstringNamed benchmark run the thresholds and power figures come from (currently full_v4).image
image.sha256hex(64)SHA-256 of the exact bytes received, the chain-of-custody anchor. Any edit or re-export changes it.image.filename / mime_type / byte_sizestring · string · intAs received. Dimensions are null when the container can't be parsed.primary & supporting[]
primary.idenumcf_finetuned: the calibrated fine-tuned detector whose score the verdict is based on. Pinned by checkpoint hash.supporting[].idenumcommunity_forensics (stock) · sdxl_detector. Independent corroboration; they never drive the verdict.primary.venue / supporting[].venuestringPublication venue or provenance (CVPR 2025 lineage, community). Cite-ready.primary.score / supporting[].scorefloat [0,1]1.0 = confident AI-generated, 0.0 = confident real photograph. A low supporting score does not weaken the verdict; stock models lag on 2024+ generators.decision
decision.fpr_cap0.05 | 0.01The false-positive budget you chose.decision.thresholdfloatOperating threshold calibrated for this cap UNDER THE ESTIMATED CONDITION so every real source in the benchmark stays within the cap. Never the naive 0.5, and different per condition.decision.verdictenumai_flagged_strict (≥ strict threshold) · ai_flagged (≥ standard threshold at the 5% cap) · not_flagged.decision.tpr_at_capfloatDetection rate measured at exactly this threshold on the calibration run. It tells you what a flag's absence is worth.robustness & limits
robustness.estimated_conditionenumDegradation condition estimated from the encoding fingerprint: clean · jpeg_q70 · jpeg_q50 · resize_50 · whatsapp · screenshot · social_chain.robustness.honesty_gapfloatHeadline AUC minus tpr_at_cap: the share of benchmark performance that does not survive your evidentiary standard. Printed, not hidden.robustness.per_degradation[]arrayDetection rate at ≤5% FPR for every condition, so you can see how power moves if the image history differs from the estimate.limits[]string[]Plain-language caveats, always present. These are the questions opposing counsel will ask; we answer them first.sampleobject?Present only on simulated demo output: { simulated: true, note }. Real analyses never carry it.