Decode on device
ML Kit, ZXing, or AVFoundation. The photo never has to leave the phone.
Fast path < 500 ms
Real-time URL safety API for QR scanners and AI agents. One API call before openURL, or before your agent fetches the payload.
1,000 checks a month. No card. Sandbox block works today.
Going to production? The first 200 Pro seats are $9.95/mo, kept. See the launch offer
The SkanQRCode API never logs the URLs you check, and we never sell your data. How we handle data
Not VirusTotal. Commercial use allowed. Text payload only, no image or photo uploads required.
// Press Check, this hits a real backend.
# decode locally, or let your agent decide, then:
var req = URLRequest(url: URL(string: "https://api.skanqrcode.com/v1/check")!)
req.httpMethod = "POST"
req.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
req.httpBody = try JSONEncoder().encode(["target": url])
let (data, _) = try await URLSession.shared.data(for: req)
let result = try JSONDecoder().decode(CheckResponse.self, from: data)
if result.action == "block" { return } // never UIApplication.shared.open(url)Product
ML Kit, ZXing, or AVFoundation. The photo never has to leave the phone.
Send the payload text. Fast path is cache, feeds, domain age, lookalike, three hops.
allow, warn, or block, before openURL. Sandbox block is free; production licensing is Pro.
VirusTotal
Analyst UI. Thirty seconds.
Great after the fact. ToS fights commercial camera apps. Too slow for the moment between decode and open.
SkanQRCode
JSON in under 500 ms.
Built for the camera path and the agent tool-call path. Commercial from day one. Fast path is cache, feeds, NRD, lookalike. Deep path is opt-in.
A commercial alternative to the VirusTotal API and Google’s own Safe Browsing API, both built for research and browser vendors first, and both gated by commercial usage limits that a scanner or agent shipping at volume runs into fast.
The problem with feeds
We keep a local copy of threat feeds with hundreds of millions of known-bad URLs. That list is useful, and it is also always behind. Most phishing URLs do their damage and disappear before any feed ever hears about them.
Feed match
Hour 6+
Confirms yesterday’s attack.
A URL only lands in a feed after enough people already reported it. For a link with a median life of 5.5 hours, that confirmation usually arrives after the campaign is already done.
SkanQRCode
Minute 0
Scores the URL nobody has reported yet.
Our proprietary scoring algorithms run domain age, brand-lookalike detection, and shortener unwinding on every check, not just the ones already on a list. That is what catches the zero-day link, the one that is one hour old and has never been seen anywhere before.
Sources: Lee et al., 7 Days Later, WWW 2025, ACM · Oest et al., Sunrise to Sunset, USENIX Security 2020 · Drury et al., Dating Phish, ARES 2022, ACM · Han, Kheir, Balzarotti, PhishEye, ACM CCS 2016 · Lim et al., Analyzing DNS Abuse for Phishing Attacks, 2025
Accuracy, continuously
No scoring system is perfect. Ours is tuned for high accuracy, but false positives and false negatives can still happen, so we treat minimizing both as ongoing work, not a number to quote once. A checked URL does not stop being worked once the fast path answers: it keeps getting re-scored in the background, so the next lookup, and the ones already cached, get better.
Domain age, DNS, and reputation signals change by the hour. We keep re-running the score in the background, not just once at request time.
Slower, opt-in checks (screenshots, WHOIS history, certificate detail) dig further into a host and feed back into that host’s future fast-path verdicts.
If a URL you checked gets raised to suspicious or malicious later, we push it to your endpoint within minutes, not the next time you happen to check it again.
Verdict-change webhooks ship on Pro and Business. Not available on Free.
For AI agents
A browsing agent, an inbox assistant, or anything that follows a link from a tool result or a scraped page can be steered by a malicious URL the same way a person tapping a QR code can. Whatever decides to fetch a URL should ask us first, before it does.
Direct API
The same /v1/check endpoint above. Call it from a LangChain or LlamaIndex tool, a custom agent loop, or wherever your code decides which links to fetch.
MCP server
Drop-in for Claude Desktop and other MCP-compatible clients. No custom tool code, no prompt engineering around it, just a verdict before the fetch.
# what the agent gets back
{
"verdict": "malicious",
"action": "block",
"mode": "url",
"reasons": ["ACTIVE_THREAT_FEED_MATCH", "KNOWN_MALWARE_MATCH"],
"cached": false,
"executionTimeMs": 38,
"environment": "production",
"licensedForProduction": true,
"requestId": "req_01J9Z8QAENP0S2"
}Agent API and MCP are on every plan, 1,000 requests/mo free. Pro and Business raise the ceiling and add production licensing.
Pricing
Sandbox action: block and the MCP server are free, so you can verify the integration before you pay for it. A production license, higher limits, and verdict-change webhooks live on Pro.
Free
$0/mo
1,000 API calls / mo
Wire it up. Test every verdict, sandboxed.
Pro
$19.90/mo
50,000 API calls / mo
The app is live. You can stop the open.
Then upgrade in the dashboard. First 200 seats: $9.95/mo, kept.
Flexible overages at $0.001 per additional check, so production never throttles.
Business
$169.90/mo
500,000 API calls / mo
Volume is the product.
Get a key
If you scan QRs and then open whatever fell out, make the check before the open. The free key works now, in sandbox, with real verdicts.
Free API key
1,000 checks a month. No card. Sandbox block works today.
Get a free API keyGoing to production? The first 200 Pro seats are $9.95/mo, kept. See the launch offer
FAQ
Gone phishing
Every QR code is a hook until something checks it.