How scam.ai verifies hiring candidates and insurance claims with TinyFish
At a glance
- Company: scam.ai (Reality Inc., Berkeley), deepfake and synthetic-media detection for video, voice, images, and documents
- Use case: Verifying hiring candidates and insurance claims before a human sends an offer or approves a payout
- Why TinyFish: A source on every result, text-only queries the parser controls, and honest per-URL failures, so acquired evidence can be held to the same standard as a detector output
- TinyFish products: Search and Fetch, with a separately authorized lane for Agent and Browser
- The split: TinyFish acquires and reads the public web. Reality binds each source to the case, checks the file, and writes the limits. The reviewer decides
The problem
Is this résumé real? Is this person who they say they are? Did this repair shop actually issue this estimate, and is $40,180 the number they wrote?
A recruiter with an offer ready and an adjuster with a payout button in reach are asking the same shape of question. Both have a file. Both have a name attached to it. Both can search the web.
And both will get a confident answer that's wrong, because the tools split the question in half. Fraud tools answer one part: is this file fake? Search tools answer the other: what does the web say? Neither half, alone, is enough to send an offer or pay a claim.
Each half also fails quietly. A page with the candidate's name on it might belong to someone else with that name. A repair shop's website proves the shop exists, not that this estimate came from it. And "no result" is not clearance. It just means the search didn't find anything.
Can we verify this? → What exactly did we verify, and what's still open?
That second question is the one Reality is built to answer, and the rest of this is how.
The integration : one résumé at a time
Xingyu (Alex) Shen authorized a public self-review of his own footprint. His résumé plus two anchors he supplied, a GitHub handle and a personal domain. No prebuilt profile, no source list, no golden answer. Here's what happened to it.
Stage 1, the packet opens. Case, role, jurisdiction, a named reviewer, and the things the pipeline is forbidden to infer: no ranking, no personality, no culture fit, no protected traits. If any of that's missing, the run ends before it starts.
Packet says: AUTHORIZATION_REQUIRED
Stage 2, the résumé becomes rows. Each school, employer, role, and project becomes its own claim. The two anchors are extracted. Anything secret, an ID number, an address, the PDF body itself, is stripped before a single query exists.
Stage 3, TinyFish goes and gets it. Seven Search calls, built by combining the handle, the domain, project names, and institutions, returned 46 ranked positions. Seven pages selected and fetched, 7 of 7: GitHub, portfolio, arXiv, Duke, DKU, Scholar. 40,266 characters and 673 links, each hash-bound to its URL and retrieval time. LinkedIn, X, and unselected leads stayed visible in the source directory without being promoted to facts.
If a page had failed, it wouldn't have vanished. It'd be a per-URL miss with a timestamp.
Packet says: SOURCE_UNAVAILABLE
Stage 4, Reality decides what belongs to whom. Every source gets bound to the case and tested: does this page actually support the claim it's attached to? 7 of 7 checks passed. Fourteen reviewer rows came out, each with a link and a limit.
Then the part that matters. In a blind rerun with a different résumé, the pipeline found a real second person with the same name. It did not merge him. He sat in an unassigned cluster where the reviewer could see him.
Packet says: AMBIGUOUS_ENTITY
Stage 5, the file check. This slice ran no image, video, or PDF model, and the packet says so in those words. An unrun check has no score. It doesn't get rounded to "fine."
Packet says: MEDIA_UNRESOLVED
Stage 6, the reviewer gets a packet. Four inspectable projects. A strongest match in systems and orchestration, another in ML and data pipelines. For each, a suggested interview question: which component did you own, and what failure changed the design.
Packet says: EVIDENCE_PACKET_READY. Enough to choose an interview. Not enough to choose an offer.
The same pipeline on a repair estimate
Fictional claim TF-VC-027, a 2011 BMW X3, partial VIN pattern from an NHTSA training set. No claimant, no loss facts, no photos.
A reusable Python runner generated three queries from year, make, model, and trim, then enforced carrier-approved domains before any call. Nothing in it branches on BMW. Three Search calls, 20 positions, 3 of 3 fetched: NHTSA vPIC, NHTSA recalls, BMW press. 4,078 + 4,927 + 17,883 characters, 50 links. Zero Agent or Browser calls.
The full VIN never entered a query. Year, make, model, trim did all the work.
Reality passed 3 of 3 checks. Supported: 2011 X3 xDrive35i, AWD, 3.0L, 300 hp. Four recall records, labelled as model-year context, explicitly not proof this vehicle is affected. Then the completeness gate: full VIN, coverage, loss facts, original media, estimate and invoices, carrier history. Six groups missing, each with the reason the adjuster needs it.
Packet says: FIRST_PARTY_VERIFICATION_REQUIRED. Not payment-ready. Continue intake. Don't approve, don't deny, don't infer the vehicle from public context.
Blind rerun on a Kia with two images and a PDF: 4 Search, 4 Fetch, no BMW fixture readable. Two PDF engines disagreed on the estimate and that disagreement was recorded, not resolved. The image adapter was unavailable, so nothing passed.
Packet says: CONFLICTING_EVIDENCE. And, separately, MEDIA_UNRESOLVED.
Why it stops: fifteen named terminal states
Most pipelines have one success state and one error. Reality's contract has one success state and fifteen named reasons to stop:
That grid is the whole design. "No public result" and "detector not run" show up in the packet as exactly what they are. Neither becomes clearance, suspicion, or a silent pass. A thin public footprint, normal for most interns and private-sector candidates, is an ordinary outcome and never a negative signal.
The contract calls it the truth boundary: the pipeline guarantees an honest state, provenance, and a next route. It does not guarantee the web has the answer, that every page was retrieved, that fetched content is true, or that a decision is correct.
Who owns what in the integration
| Need | Reality | TinyFish |
|---|---|---|
| Find public context | Compiles minimum queries under a domain allowlist | Search returns ranked sources with position |
| Read the sources | Verifies attachment and support, binds hashes | Fetch returns content, links, time, per-URL status |
| Keep private data out | Parser strips VINs, IDs, file bodies | Text queries only |
| Reach logged-in sources | Separately authorized, tenant-isolated lane | Web agent and browser sessions for agents, when enabled |
| Check the file | Real_pdf, EVA, hash-bound receipts | Not TinyFish's job |
| Decide | Reviewer, limits written in | Not anyone's job but the human's |
Three things Reality needed from a web layer, and why Search and Fetch fit: every result carries its URL and retrieval time, so provenance is free. Queries are text the parser writes, so nothing leaves the boundary that wasn't put there. And a page that doesn't come back is a recorded miss, not a gap.
What's next
scam.ai wants to take the same evidence pattern into the two scenarios it's filming now: a recruiter checking a candidate's public context and interview video before sending an offer, and an adjuster checking an issuer and a $40,180 estimate before approving a payout. In both, TinyFish supplies the public context, Reality checks the file, and a person takes the next step. After that, the roadmap moves the logged-in lane from planned to live, so a candidate's private repo or a carrier's portal can enter the packet through TinyFish Agent and Browser with the same provenance rules as everything else.
For the engineering side of the integration, read scam.ai's technical write-up of how Reality binds TinyFish receipts to a case.
Building an agent that needs to prove what it found?
Talk to Us | Explore the Playground
FAQ
Does TinyFish decide anything? No. TinyFish finds and reads public pages. Reality verifies what those pages support. The reviewer decides. The contract sets automatic_decisions: false.
What if the web has nothing on the person? That's an ordinary outcome, recorded as INSUFFICIENT_PUBLIC_EVIDENCE. It's never a negative signal. The next step is to ask the person or an authorized first party.
What happens to private data? Full VINs, ID numbers, and file bodies never enter a public query. Uploads are deleted after processing, fetched bodies aren't persisted, reports expire in 24 hours.
Can it read login-gated sources? Only through a separately authorized lane using TinyFish Agent or Browser Context Profiles with customer-owned credentials. Neither recorded run used it.
Does it detect deepfakes in interview video? Not yet. The contract lists face-swap detection under "not implemented here." It's one of the two film scenarios being recorded.
TinyFish · web search API · web fetch API · multi-step web tasks · browser sessions for agents · scam.ai
AI disclosure
Content on this website may be created or refined with the assistance of AI tools and is subject to human editorial review.



