Verdetto Threat API: Python SDK
Check links, domains and crypto addresses against Verdetto's listings and other sources. The signed lists sit on your machine, so most checks send nothing.
Install
pip install verdettoqr-threat==0.1.2
First check
from verdettoqr_threat import Verdetto
v = Verdetto()
a = v.check("https://listed.test.verdettoqr.com/login")
print(a["status"]) # "listed"
No key and no setup. A test host is answered with no request; for other links, the first check downloads the lists, and a check after an hour refreshes them.
not_listed means no current listing matched, nothing more.
Live checks
v = Verdetto("vtk_open_...") # or set VERDETTO_API_KEY
a = v.check_live("https://example.com/sign-in")
Get an Open key at verdettoqr.com/api. A timeout and retries are set for you.
Answers
Every answer is a dict with status, checked_at and matches.
status |
Meaning |
|---|---|
listed |
One of our listings matched. |
listed_by |
Another source matched, ours did not. |
not_listed |
No source matched. |
snapshot_stale |
The lists are past their age and nothing was sent; see code. |
rate_limited |
Held to retry_after_s. |
error |
See code; retry_after_s when the API sent one. |
is_listed(a) is true for listed and listed_by. route is local or live; past the lists' age, live_on_stale asks the API.
A local match of ours carries listing_id in place of category; with_evidence(a) adds its category and evidence.
history() answers ok with listings in place of matches; truncated when more than 60 match.
Errors
A lookup does not raise: an answer that is not a verdict carries code.
code |
What to do |
|---|---|
invalid_input |
Not a link, domain or address. Nothing was sent. |
network |
No answer came. Try again later. |
http_error |
The answer was not the API's. Try again later. |
rate_limited |
Wait retry_after_s. |
held |
An earlier 429 holds it. Wait retry_after_s. Nothing was sent. |
never_synced |
No lists yet. Call sync(). |
stale |
The lists are past their age. Call sync(), or set live_on_stale. |
Any other code is the API's, with http_status: see Error codes.
An API code comes with its title and detail, in your language; the SDK's own codes have neither.
A failed sync keeps the lists it holds and tries again later. sync() gives its code; snapshot_stale carries it.
code |
What to do |
|---|---|
fetch_failed |
The lists' host did not answer. It tries again. |
not_in_manifest |
A file is not in the signed manifest. It tries again. |
file_mismatch |
A file does not match its hash. It tries again. |
unparsable |
A manifest does not parse. It tries again. |
signature |
A manifest is not under the pinned key. Update the SDK. |
no_suffix_list |
The lists have no suffix list. It tries again. |
format |
A format this version cannot read. Update the SDK. |
expired |
The lists have expired. It tries again. |
older |
Older than the lists held. It tries again. |
error |
Another fault; reason says which. It tries again. |
Retry-After:
- A 429 is not sent again. Live calls wait its
Retry-Afterand answerrate_limited, codeheld, until then. With the hintbatch, single calls alone wait. - A 5xx with the API's
codecomes back at once, withretry_after_s. - A network fault, or a 5xx without a
code, is sent again up tomax_retriestimes. ARetry-Afterup to 30 s is waited out; a longer one comes back asretry_after_s.
Methods
| Method | Does |
|---|---|
check(url) |
A link, from the lists. |
check_many(urls) |
Many links, in order. |
check_domain(domain) |
A domain, from the lists. |
check_address(address) |
A crypto address, from the lists. |
check_live(url) |
A link, from the API. |
check_live_many(urls) |
Many links, from the API, in batches. |
history(url_or_domain) |
Our listings and their dates, from the API. |
with_evidence(a) |
Our listings' evidence for an answer. |
record(listing_id) |
One listing's record. |
sync() |
Fetch the lists now. |
snapshot() |
The lists' version and age. |
Options
v = Verdetto("vtk_open_...", live_on_stale=True, timeout_s=5)
| Option | Default |
|---|---|
key |
VERDETTO_API_KEY |
live_on_stale |
False |
timeout_s |
10 |
max_retries |
2 |
max_age_s |
10800 (3 h) |
auto_refresh |
True |
base |
https://api.verdettoqr.com/ |
bundle_base |
https://bundle.verdettoqr.com/ |
fetch |
urllib |
language |
none |
public_key, retry_base_s, own_full_max, now, sleep |
for tests and other signers |
language: a BCP 47 tag or a list, first preferred, sent to the API as Accept-Language: language=["de-AT", "en"].
What is sent
- The lists: GETs from the bundle host, with no key and no input:
list.json, the suffix list,api/list.jsonand the files it names. check,check_many,check_domain,check_address: nothing. In a list past 50,000 of our listings, a hit reads one file named by 3 hex digits of its hash.- With
live_on_stale, a link or domain past the lists' age goes to the API. record,with_evidence: the record index once, then the record's file, from the bundle host.check_live,check_live_many,history: a POST to the API with the input and the key. An input it would refuse is not sent.- Every request:
User-Agent: verdettoqr-threat-python/0.1.2. The API's also:Content-Type: application/json,Authorization: Bearer <key>, andAccept-Languagewhenlanguageis set. - Your HTTP stack adds its own, such as
Host.
Test hosts
listed.test.verdettoqr.com answers listed. clear.test.verdettoqr.com answers not_listed.
Runs on
Python 3.11 and up. One client may be shared across threads. No dependencies; pip install verdettoqr-threat[fast] adds cryptography for a faster signature check.
License
Code: MIT. Our listings: CC0 1.0. Other sources: their own terms, in the lists' manifest.
Metadata
Release files for verdettoqr-threat 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| verdettoqr_threat-0.1.2.tar.gz | 40.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| verdettoqr_threat-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 72.2 kB
Release files / verdettoqr_threat-0.1.2.tar.gz
| Download URL | verdettoqr_threat-0.1.2.tar.gz |
|---|---|
| Size | 40.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3d8653df980ed717e210911d3b4825b2b38636a8c4327cdc1d04ce398fb8a97b
|
|
BLAKE2b-256 checksum How to use checksums |
e3f7fc4f3d1a222194bb10326048efb422b340be398896107d91ab3efcfbb2f8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.17
|
Release files / verdettoqr_threat-0.1.2-py3-none-any.whl
| Download URL | verdettoqr_threat-0.1.2-py3-none-any.whl |
|---|---|
| Size | 31.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
09aba33699d780a9ce814549825c51a0e55aef9bd4ab9e6a02230e5778a2bbab
|
|
BLAKE2b-256 checksum How to use checksums |
8b2c1bdef777fd08175d0b2f679291072fa6e0e556485ca28b70174a8c6872d7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.17
|
Security for verdettoqr-threat 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.