Verifyd API
Every verdict comes with a color, a plain-language headline, the reasons behind it, and where possible an original: the link a reader should go to instead. The machine-readable spec is at /openapi.json.
Keys and limits
Send your key in the x-api-key header (or Authorization: Bearer …). Keys look like swv_live_ followed by 32 characters and are shown once when issued. Email hello@planckchron.com for one.
| Request | Units |
|---|---|
| Image, each (single or in a batch) | 1 |
| Link check / deep link check | 1 / 3 |
| Claim, quick (fact-checks only) / deep (with sources) | 1 / 2 |
| Find the original of a picture | 2 |
| Add a speech | 10 |
| Match a video against checked speeches | 1 (2 with the file) |
Daily limits by tier: starter 1,000 units, growth 25,000, platform 500,000. Responses include x-ratelimit-limit and x-ratelimit-remaining. Over the limit you get 429 with Retry-After (seconds until 00:00 UTC). Invalid or revoked keys get 401. Without a key, requests are limited per visitor per minute, which suits a browser but not a backend.
Verdicts
| level | color | Means |
|---|---|---|
verified | green | Valid Content Credentials signed by an issuer on the trust list |
ai | red | Declared AI-generated (credentials or metadata), or detected with high confidence |
false | red | Impostor site, or claim rated false or contradicted |
caution | amber | Edited, recycled from an older context, invalid credentials, disputed |
unknown | gray | No signal either way. Not a verdict. |
The original object, when present: { kind, label, url, why }. kind is one of real-article, real-site, fact-check, source, first-seen, credentials, origin or search. A url starting with / is relative to the API's address.
POST /api/verify/media
One image by url or base64 data + mime, or items with up to 12. Pass pageUrl so recycled pictures can be recognised.
curl https://YOUR-HOST/api/verify/media \
-H "x-api-key: $SWV_KEY" -H "content-type: application/json" \
-d '{"url":"https://cdn.example/upload.jpg","pageUrl":"https://example.com/post/1"}'
{
"kind": "image", "level": "caution", "color": "amber", "label": "Seen before",
"headline": "This picture appeared on another site more than a year earlier.",
"reasons": [{ "tone": "warn", "title": "First seen 4 Mar 2021", "detail": "on regional-tribune.example" }],
"original": { "kind": "first-seen", "label": "See where it first appeared",
"url": "https://regional-tribune.example/2021/03/04/river-floods", "why": "First seen on …" },
"canFindOriginal": false
}
POST /api/verify/original
Reverse image search for where a picture came from. Prefers the earliest dated page carrying the exact picture; never offers look-alike sites or the page it was found on. Results are cached for a week. Returns { original, alternatives, bestGuess, searched, verdict }. Call it when a media verdict has canFindOriginal: true.
POST /api/verify/page
{ "url": "…", "deep": false }. Catches domains imitating news outlets (swapped letters, extra words, homoglyphs, punycode) and links to the genuine article; checks the headline against fact-checks; checks the lead image.
POST /api/verify/claim
{ "text": "…", "deep": true }. Published fact-checks first; with deep, independent sources are read and "supported" requires two independent sites.
Speeches: POST /api/speech
Add a speech once (API key required); it is checked and published, and the stamp appears everywhere the speech is posted. Costs 10 units.
{ "title": "Rally speech, Dayton", "speaker": "A. Candidate", "org": "Candidate for Senate", "eventDate": "2026-10-30",
"sourceUrl": "https://campaign.example/speeches/dayton",
"links": ["https://www.youtube.com/watch?v=…", "https://x.com/…/status/…"],
"mediaUrl": "https://…/speech.mp4", // or "data" (base64) + "mime" for files under 3 MB
"captions": "WEBVTT\n\n00:00:01.000 --> …" // or "transcript": "plain text"; omit to transcribe
}
Returns the speech with word, simple, claims[] (each with t, verdict, word, by: the fact-checker, rating and link) and page. Large files: POST /api/speech/upload-url first, PUT the file to the returned address, then send its mediaUrl.
GET /api/speech lists checked speeches; GET /api/speech/item?id=… returns one. POST /api/speech/match with { pageUrl, videoSrc } tells a player or extension whether a video is a checked speech (matched by address or by frame fingerprints) and returns it.
Rules. Verifyd never judges a political claim itself. A claim is TRUTH, FALSE or DISPUTED only when a fact-checker has published that rating (ClaimReview data), and the stamp links to it. Everything else is UNCHECKED, which is not a verdict. Footage checks (Content Credentials, AI metadata) outrank what is said: AI footage is stamped AI whatever the speaker says.
Errors
Errors are JSON: { "error": "…" } with status 400 (bad input), 401 (key), 413 (body over 4.5 MB or image over 15 MB), 415 (not an image), 422 (empty or unreachable image), 429 (limit), 5xx (retry with backoff).
Publisher badge
Add one script and mark the images to badge. Credentialed photos get a green badge linking to their signed record; add data-verifyd="all" to show gray badges too.
<script src="https://YOUR-HOST/badge.js" async></script> <img src="/photos/harbour.jpg" data-verifyd alt="Fishing boats at dawn">
Health
GET /api/health returns { ok, database, checks, storeUrl } and status 503 if the database is unreachable. GET /api/verify/status lists which checks this deployment runs.