U UploadCheck Check a file free →
Guides · What Broke

What a signed PASS/BLOCK media QC receipt is — and how a CI pipeline gates on it

UploadCheck · media QC receipts

A signed media QC receipt is a tamper-evident record of a quality-check verdict — PASS, WATCH, or BLOCK — bound to the exact file it checked via that file's sha256 hash and the named profile it was checked against. Because the whole record is signed, a CI pipeline or an AI agent can gate its publish step on media quality the same way a signed status check gates a code merge: no asset ships without a green receipt.

The problem: media has no "required check"

Code has this solved. A pull request can't merge until the tests pass, the linter is green, and the required status checks report success. The gate is enforced — not "here's some advice a human reads," but "this blocks the merge."

Media pipelines usually have no equivalent. An AI-video pipeline generates a clip, an editor exports a cut, an ad tool spins up a hundred variants — and the only quality gate is someone eyeballing it, if that. So a caption clipped by the platform UI, audio that cuts out at 0:08, a frozen frame at a stitch seam, or a morphing hand ships to a paying audience. The failure is caught after publish, in a refund or a re-render, instead of before.

A QC report is a step up, but it's still just data a human interprets. What turns quality into a required check is a verdict a pipeline can act on automatically and prove afterward. That's the receipt.

What's in a receipt

Run UploadCheck on a finished export against a named profile, then fetch the receipt for the completed job. It's a small, signed JSON object:

{
  "schema": "uploadcheck-receipt/1",
  "verdict": "PASS",
  "sha256": "<the checked file's hash>",
  "profile": "youtube_shorts",
  "gates": ["av_sync", "canvas_fill", "loudness", "shorts_format"],
  "blocked": [],
  "jobId": "job_...",
  "issuedAt": "2026-07-20T00:00:00.000Z",
  "issuer": "uploadcheck.app",
  "signature": "sha256=..."
}

Four things make it a gate rather than a report:

How to gate a pipeline on it

The UploadCheck CLI and GitHub Action already exit non-zero on a BLOCK verdict, which fails the build. Add the receipt so the run also produces a verifiable artifact:

# CLI — fails the job on BLOCK, and writes the signed receipt
uploadcheck check final.mp4 \
  --profile youtube_shorts \
  --fail-on block \
  --receipt uploadcheck-receipt.json

In GitHub Actions, the same thing as a step:

- uses: uploadcheck/action@v1
  with:
    file: dist/final.mp4
    profile: youtube_shorts
    fail-on: block
    receipt-path: uploadcheck-receipt.json
    api-key: ${{ secrets.UPLOADCHECK_API_KEY }}

The job fails if the verdict is BLOCK; on PASS it continues and leaves uploadcheck-receipt.json for a later step to upload as an artifact or hand to a downstream deploy. An AI agent does the same through the qc_get_receipt MCP tool and gates its own publish action on receipt.verdict === "PASS".

Verifying a receipt later

The point of a signature is that trust doesn't depend on the transport. Anyone handed a receipt can confirm it's authentic and unaltered:

curl -X POST https://api.uploadcheck.app/v1/public/receipts/verify \
  -H "content-type: application/json" \
  --data @uploadcheck-receipt.json

The endpoint — no authentication, no account — recomputes the signature and reports whether the receipt is genuine. Then confirm the receipt's sha256 matches the file you're about to publish, and the chain is complete: this verdict, for this exact file, against this named spec, provably issued by UploadCheck.

Named delivery profiles

Check against a target your pipeline recognizes so the receipt names a spec, not a checklist. Available profiles include youtube_shorts, youtube_longform, meta_reels_ad, tiktok_post, broadcast_r128, podcast_delivery, and ai_render_gate. See the receipts documentation for the full list and the fields each one checks.

An honest note on what UploadCheck checks. UploadCheck inspects a finished file for publish-readiness problems and reports what it finds with timestamps; it does not claim to detect that a clip was AI-generated, and it does not guarantee it catches every possible defect. The receipt records the verdict for the gates that ran — real, reproducible evidence, not a promise of perfection.

Why this is the unlock

A report tells you what's wrong. A signed, file-bound, named-target receipt lets a pipeline run unattended — generate, check, gate, publish — and prove afterward that every asset passed a specific spec. That's the leap linters and CI status checks made for code: from advice to this blocks the deploy. For anyone shipping media at scale — AI-video pipelines, ad-variant factories, localization houses — it's the difference between hoping the output is clean and requiring it.

Gate your next publish on a signed receipt.

Check a file free

Free with your email — 40+ quality gates, 200 checked minutes a month. Read the receipts docs or the full API & MCP reference.