VestigeForensics

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.

MethodPath
POSThttps://vestigeforensics.com/api/v1/token
POSThttps://api.vestigeforensics.com/v1/analyze
GEThttps://vestigeforensics.com/api/v1/usage
DELETEhttps://api.vestigeforensics.com/v1/reports/{report_id}
POSThttps://api.vestigeforensics.com/v1/analyze/batchcoming soon

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.

application/json
{
  "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.

shell
sha256sum image.jpg
# 9f2c...  image.jpg

2Exchange your key for a token. This is the call that spends one analysis, whether or not you go on to use the token.

shell
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.

shell
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 right

LimitsUploads 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.

StatusHostMeaning
400Accountsha256 missing or not a lowercase 64-character hex digest.
401AccountAPI key missing, malformed, unknown, or revoked. All four answer identically.
401AnalysisAnalysis token missing, expired, or not signed by us. Tokens last ten minutes.
403AnalysisThe uploaded bytes do not hash to the sha256 the token was issued for.
413AnalysisImage over 15 MB or over 50 megapixels.
415AnalysisThe upload could not be decoded as an image.
422Analysisfpr_cap was not 0.05 or 0.01, or condition was not a known value.
429AccountQuota for the period is spent. The body carries used, limit, and resetsAt.
429AnalysisToo 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
Start your free trial

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
Read the API docs

Enterprise / Forensic

Coming soon

Customannual

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.