# Grainmark > Capture-time media provenance. Seal a photo or video when you record it. Later, anyone with the file and its sidecar can ask whether a copy is still that media. Grainmark is the product (was Proofsheet until 2026-09-20). The protocol underneath is VRC-48M. This is not a wild-stream deepfake detector and it does not scan the internet for synthetic video. A match is an unsigned visual comparison against a sidecar or a seal this host still holds — not a camera signature, trusted timestamp, or a claim that the scene was never generated. Canonical host: https://grainmark.app Alias (do not 301 POST /api/*): https://proofsheet.rick3.dev Source: https://github.com/rrhoopes3/VRC48m Contact: hello@rick3.dev ## Pages - [Home / demo](https://grainmark.app/): seal, verify a copy, or compare two files - [Verify tab](https://grainmark.app/?tab=verify): same demo, Verify panel - [Studio](https://grainmark.app/studio): editor + seal + sidecar download - [Privacy](https://grainmark.app/privacy): what is uploaded, what is kept, private vs published - [This file](https://grainmark.app/llms.txt): agent discovery (also /llm.txt and /.well-known/llms.txt) ## What a green / AUTHENTIC result means - Full-frame visual descriptors on the overlapping interval (identity / modest same-aspect scale). - Honest recompression (JPEG ≥ Q40), brightness, blur, typical transcode. - `PARTIAL` is three stored probe JPEGs on a crop/reframe — not frame-by-frame coverage. Do not treat PARTIAL as a full match. - Audio and playback timing are not compared. - `confidence` is a matching fraction under threshold 0.16, not P(authentic). ## API (JSON envelope `{ok, data}` / `{ok, error}`) Base `https://grainmark.app`. CORS `*`. No accounts, no API keys, no rate limit. Caps: 200 MiB, 20 s, 600 frames, 2 concurrent jobs (`429`). New seals are **private until published**. Sharing a sidecar shares three embedded JPEG probes. | Method | Path | Notes | |--------|------|--------| | POST | `/api/vrc48m/anchor` | multipart `file`; optional `publish=true`, `source_url`. Returns `anchor_id`, `sidecar` (keep this), `access_token` (once). The HTTP envelope is not a sidecar. | | POST | `/api/vrc48m/verify` | multipart `file` plus either sidecar file `anchor` **or** `anchor_id` (unpublished needs `token`). | | POST | `/api/vrc48m/compare` | multipart `original` + `suspect`. No registry. | | GET | `/api/vrc48m/anchors` | published seals only; labels are `Anchor `, not filenames. | | GET | `/api/vrc48m/lookup` | `?sha256=` or `?url=`; published only. | | GET | `/api/vrc48m/anchor/` | published metadata; no probes. | | GET | `/api/vrc48m/anchor//download` | portable sidecar; published or `token`. | | POST | `/api/vrc48m/anchor//publish` | form/query/`Authorization: Bearer` token. | Token: form `token`, query `?token=`, or `Authorization: Bearer`. Sidecar-only verify works on any host that never held the seal. Do not add fetch-by-URL. Live Socket.IO capture is off unless `VRC48M_LIVE_STREAM=1` (public host must not set that). ## Optional curl ``` curl -sS -F "file=@clip.mp4" https://grainmark.app/api/vrc48m/anchor # keep .data.sidecar and .data.access_token curl -sS -F "file=@clip.mp4" -F "anchor=@clip.grainmark.json" https://grainmark.app/api/vrc48m/verify ``` ## Key facts - Python package remains `vortexchain`; HTTP paths remain `/api/vrc48m/*`. - iOS bundle id is still `proofsheet.rick3.app` until a new App Store listing. - There is no MCP server and no Muse connector on this host. - Grey-cloud DNS on purpose: Cloudflare's proxy caps uploads at 100 MB; this API allows 200 MB.