A lightweight Python SDK for the Validin API
Project description
Validin Python SDK
A Python SDK for the Validin API, designed to enable large-scale monitoring and enrichment workflows.
Requirements
- Python 3.9+
- A Validin API key
Installation
pip install validin-python-sdk
from validin import Client
Configuration
The client requires an API key. The simplest approach is to set environment variables:
export VALIDIN_API_KEY="your-api-key"
Enterprise users must also set their endpoint:
export VALIDIN_BASE_URL="https://your-enterprise-endpoint.example.com"
You can also pass these directly to the client:
from validin import Client
client = Client(api_key="your-api-key", base_url="https://your-enterprise-endpoint.example.com")
If base_url is not provided, the client defaults to https://app.validin.com.
Quick Start
Monitor a DNS TXT record query and add new results to a project:
from validin import Client
client = Client()
results = client.extra_history("anthropic-domain-verification*", lookback=1)
client.add_to_project("YOUR_PROJECT_ID", results.values)
For more advanced workflows, see the examples/ directory.
Core Concepts
Indicators
An Indicator represents a queryable entity: a domain, IP address, hash, or raw string. The SDK automatically infers the type from a string, so you can pass raw strings directly to any client method:
client.dns_history("example.com") # inferred as domain
client.dns_history("1.1.1.1") # inferred as IP
client.extra_history("some-txt-value*") # inferred as string (wildcard)
ResultSet
A ResultSet is the container returned by every query method. It provides:
- Iteration — loop over individual records (
for record in results) .keys— deduplicated list ofIndicatorobjects from each record (the domains/IPs represented).keys_str— string values of.keys.values— deduplicated list of record values.to_rows()— convert all records to a list of dictionaries.aggregate()— flatten nested bulk results into a single deduplicated ResultSet
Records
Each query method returns a ResultSet containing typed record objects. Available record types:
DNSRecordCertificateRecordHostResponseRecordScanRecordEnrichedIndicator(from reputation lookups)AnnotationRecord(nested insideEnrichedIndicator)LookalikeRecordRegistrationRecordYaraMatchRecordContent
Enriched Indicators
An EnrichedIndicator is a subclass of Indicator that carries reputation and annotation data directly on the indicator itself. You encounter enriched indicators in two places:
1. Enrichment lookups — client.enrich() returns a ResultSet where each record is an EnrichedIndicator with score, verdict, and annotations:
results = client.enrich("example.com")
enriched = results[0]
print(enriched.value) # "example.com"
print(enriched.score) # 0
print(enriched.verdict) # "benign"
print(enriched.annotations) # tuple of AnnotationRecord objects
print(enriched.to_rows()) # annotations flattened to list of dicts
For bulk enrichment, use .keys to iterate the EnrichedIndicator objects:
results = client.enrich(["example.com", "1.1.1.1", "google.com"])
for enriched in results.keys:
print(f"{enriched.value}: score={enriched.score}, verdict={enriched.verdict}")
print(enriched.to_rows())
2. History queries with annotate=True — When you pass annotate=True to dns_history(), extra_history(), host_responses(), or registration_history(), the key and value fields on returned records are upgraded from plain Indicator to EnrichedIndicator when the API provides intel data:
results = client.dns_history("example.com", annotate=True)
for record in results:
if isinstance(record.value, EnrichedIndicator):
print(f"{record.value.value} has {len(record.value.annotations)} annotations")
print(record.value.informational)
Since EnrichedIndicator is a subclass of Indicator, enriched indicators work everywhere a plain indicator does — you can pass them directly to add_to_project(), use them as input to other queries, or access .value and .type as usual.
Bulk Queries and Aggregation
Any method that supports bulk queries can also accept a list of indicators instead of a single value:
results = client.enrich(["example.com", "1.1.1.1", "google.com"])
When you pass a list, the SDK:
- Rate-limits requests to 5 queries/second
- Retries transient failures (408, 429, 500, 502, 503, 504) with exponential backoff
- Silently skips 404 responses
The returned ResultSet contains one child ResultSet per indicator. To flatten all results into a single deduplicated list, call .aggregate():
results = client.dns_history(["example.com", "google.com", "cloudflare.com"])
# Iterate per-indicator results
for child_result_set in results:
print(child_result_set.query_key, len(child_result_set))
# Or flatten into one deduplicated set
all_records = results.aggregate()
print(all_records.to_rows())
Available Methods
client.dns_history(indicator)
DNS record history for a domain, IP, or string.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/dns/history/:domain |
| IP | /api/axon/ip/dns/history/:ip |
| String | /api/axon/string/dns/history |
Supports bulk queries. Options: limit, first_seen, last_seen, lookback, annotate, wildcard, categories_include, exclude_nx.
client.extra_history(indicator)
Extended DNS record history (TXT, SPF, etc.) for a domain, IP, or string.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/dns/extra/:domain |
| IP | /api/axon/ip/dns/extra/:ip |
| String | /api/axon/string/dns/extra2 |
Supports bulk queries. Options: limit, first_seen, last_seen, lookback, annotate, wildcard, categories_include, exclude_nx.
client.host_responses(indicator)
HTTP crawl/response history for a domain, IP, hash, or string.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/crawl/history/:domain |
| IP | /api/axon/ip/crawl/history/:ip |
| Hash | /api/axon/hash/crawl/history/:hash |
| String | /api/axon/string/crawl/history |
Supports bulk queries. Options: limit, lookback, annotate.
client.enrich(indicator)
Enrich a domain or IP with reputation score, verdict, and annotations. Returns a ResultSet of EnrichedIndicator objects (one per queried indicator), each carrying score, verdict, annotations, and informational fields.
Also available as client.reputation() (alias).
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/reputation/quick/:domain |
| IP | /api/axon/ip/reputation/quick/:ip |
Supports bulk queries. No additional options.
client.lookalikes(target)
Find newly registered lookalike domains matching a domain or regex pattern.
| Target Type | API Route |
|---|---|
| Domain | /api/lookalike/domain/:domain |
| Regex | /api/lookalike/regex |
Does not support bulk queries. Options: exclude, limit (1–250), lookback (1–90 days), depth (labels, subdomains, fqdns), similarity (0–4, domain targets only).
Regex targets can be passed as a compiled re.Pattern or a slash-delimited string:
client.lookalikes("/^(t-mobile|att|verizon)\.([a-z]{5,6})\.(icu|cc)$/")
client.certificates(indicator)
Historic certificate transparency matches for a domain.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/certificates/:domain |
Does not support bulk queries. Options: wildcard, limit (1–20000), first_seen, last_seen, lookback, time_format (unix or iso).
client.ptr_history(indicator)
Historic PTR/hostname records for a domain or IP.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/dns/hostname/:domain |
| IP | /api/axon/ip/dns/hostname/:ip |
Supports bulk queries. Options: limit, first_seen, last_seen, lookback, annotate, time_format (unix or iso), and wildcard for domain queries only.
client.start_scan(find)
Start an enterprise live HTTP/S scan and return a ScanJob.
| API Route |
|---|
/api/axon/live/scan/start |
Does not support bulk queries. Options: countries, refer, user_agent.
client.get_scan(scan_id)
Fetch live scan status and return a ScanJob.
| API Route |
|---|
/api/axon/live/scan/results/:scan_id |
Does not support bulk queries.
client.scan(find)
Convenience wrapper around start_scan(). By default it waits for completion and returns a ResultSet of ScanRecord objects. Pass wait=False to get a ScanJob immediately.
| API Route |
|---|
/api/axon/live/scan/start -> poll results -> crawl |
Options: countries, refer, user_agent, wait, poll_interval, timeout.
client.registration_history(indicator)
WHOIS/RDAP registration history for a domain or string.
| Indicator Type | API Route |
|---|---|
| Domain | /api/axon/domain/registration/history/:domain |
| String | /api/axon/string/registration/history2 |
Supports bulk queries. Options: limit, first_seen, last_seen, lookback, annotate, wildcard, include_fields.
client.yara_matches(project_id, rule_id)
Fetch YARA rule match results from a project. Auto-paginates all results by default.
| API Route |
|---|
/api/project/:project_id/yara/rules/:rule_id/matches |
Does not support bulk queries. Options: page, page_size (provide both for manual pagination), include_html, first_seen, last_seen.
client.fetch_content(indicator)
Fetch stored HTML content by body hash.
| API Route |
|---|
/api/axon/hash/content/html/sha1/:hash |
Supports bulk queries. Accepts a hash string, Indicator, or HostResponse object with a body_hash.
client.add_to_project(project_id, indicators)
Add indicators to a Validin project.
| API Route |
|---|
/api/project/:project_id/indicators/add |
Accepts a single indicator or a list. Options: note, tags.
Examples
Example scripts are in the examples/ directory:
**lookalike_monitor.py**— Regex lookalike search for telecom smishing domains, filter by registrar, add to project.**dns_txt_record_monitor.py**— Monitor a DNS TXT record wildcard query and add results to a project.**bulk_indicator_enrichment.py**— Bulk enrichment lookup across multiple indicators.**ingest_yara_matches.py**— Fetch all YARA rule matches for a project and print aggregated results.**sample_host_responses.py**— Bulk host response history with HTML content download.
Error Handling
The SDK raises ApiError for HTTP failures and ValidinError as a base exception class:
from validin import Client
from validin_sdk.errors import ApiError, ValidinError
client = Client()
try:
results = client.dns_history("example.com")
except ApiError as e:
print(f"HTTP {e.status_code}: {e.message}")
except ValidinError as e:
print(f"SDK error: {e}")
API Coverage
The SDK currently covers 24 of 76 API endpoints.
| Status | Method | Endpoint | Summary | SDK Method |
|---|---|---|---|---|
| Bulk | ||||
| ❌ | POST | /api/axon/bulk/osint/context |
Bulk OSINT Context | |
| Domain | ||||
| ✅ | GET | /api/axon/domain/certificates/{domain} |
Domain Certificates | certificates() |
| ✅ | GET | /api/axon/domain/crawl/history/{domain} |
Domain Crawl History | host_responses() |
| ✅ | GET | /api/axon/domain/dns/extra/{domain} |
Domain DNS Extra | extra_history() |
| ✅ | GET | /api/axon/domain/dns/history/{domain} |
Domain DNS History | dns_history() |
| ❌ | GET | /api/axon/domain/dns/history/{domain}/A |
Domain DNS History - A | |
| ❌ | GET | /api/axon/domain/dns/history/{domain}/AAAA |
Domain DNS History - AAAA | |
| ❌ | GET | /api/axon/domain/dns/history/{domain}/NS |
Domain DNS History - NS | |
| ❌ | GET | /api/axon/domain/dns/history/{domain}/NS_FOR |
Domain DNS History - NS_FOR | |
| ✅ | GET | /api/axon/domain/dns/hostname/{domain} |
Domain DNS Hostname | ptr_history() |
| ❌ | GET | /api/axon/domain/osint/history/{domain} |
Domain OSINT History | |
| ❌ | GET | /api/axon/domain/pivots/{domain} |
Domain Pivots | |
| ❌ | GET | /api/axon/domain/pivots/{domain}/{category} |
Domain Pivots - Category | |
| ✅ | GET | /api/axon/domain/registration/history/{domain} |
Domain Registration History | registration_history() |
| ❌ | GET | /api/axon/domain/registration/live/{domain} |
Domain Registration Live | |
| ✅ | GET | /api/axon/domain/reputation/quick/{domain} |
Domain Reputation Quick | enrich() |
| ❌ | GET | /api/axon/domain/subdomains/{domain} |
Domain Subdomains | |
| ✅ | GET | /api/lookalike/domain/{domain} |
Lookalike Domain | lookalikes() |
| ✅ | GET | /api/lookalike/regex |
Lookalike Regex | lookalikes() |
| ❌ | GET | /api/v2/domain/combined/connections/{domain} |
V2 Domain Combined Connections | |
| Hash | ||||
| ❌ | GET | /api/axon/hash/content/certificate/sha1/{hash} |
Hash Content Certificate (SHA1) | |
| ❌ | GET | /api/axon/hash/content/favicon/md5/{hash} |
Hash Content Favicon (MD5) | |
| ✅ | GET | /api/axon/hash/content/html/sha1/{hash} |
Hash Content HTML (SHA1) | fetch_content() |
| ✅ | GET | /api/axon/hash/crawl/history/{hash} |
Hash Crawl History | host_responses() |
| ❌ | GET | /api/axon/hash/pivots/{hash} |
Hash Pivots | |
| ❌ | GET | /api/axon/hash/pivots/{hash}/{category} |
Hash Pivots - Category | |
| IP | ||||
| ✅ | GET | /api/axon/ip/crawl/history/{ip} |
IP Crawl History | host_responses() |
| ❌ | GET | /api/axon/ip/crawl/history/{ip}/{cidr} |
IP Crawl History - (CIDR) | |
| ✅ | GET | /api/axon/ip/dns/extra/{ip} |
IP DNS Extra | extra_history() |
| ❌ | GET | /api/axon/ip/dns/extra/{ip}/{cidr} |
IP DNS Extra - (CIDR) | |
| ✅ | GET | /api/axon/ip/dns/history/{ip} |
IP DNS History | dns_history() |
| ❌ | GET | /api/axon/ip/dns/history/{ip}/{cidr} |
IP DNS History - (CIDR) | |
| ✅ | GET | /api/axon/ip/dns/hostname/{ip} |
IP DNS Hostname | ptr_history() |
| ❌ | GET | /api/axon/ip/dns/hostname/{ip}/{cidr} |
IP DNS Hostname - (CIDR) | |
| ❌ | GET | /api/axon/ip/osint/history/{ip} |
IP OSINT History | |
| ❌ | GET | /api/axon/ip/osint/history/{ip}/{cidr} |
IP OSINT History - (CIDR) | |
| ❌ | GET | /api/axon/ip/pivots/{ip} |
IP Pivots | |
| ❌ | GET | /api/axon/ip/pivots/{ip}/{cidr} |
IP Pivots - (CIDR) | |
| ❌ | GET | /api/axon/ip/pivots2/{ip}/{category} |
IP Pivots - Category | |
| ✅ | GET | /api/axon/ip/reputation/quick/{ip} |
IP Reputation Quick | enrich() |
| Projects | ||||
| ❌ | GET | /api/project/list |
Project List | |
| ❌ | GET | /api/project/{project_id} |
Project Details | |
| ❌ | GET | /api/project/{project_id}/alerts/dates |
Project - List Dates that have Alerts | |
| ❌ | GET | /api/project/{project_id}/alerts/latest |
Project - Latest Alerts | |
| ❌ | GET | /api/project/{project_id}/alerts/{date} |
Project - Alerts for Date | |
| ❌ | GET | /api/project/{project_id}/indicators |
Project - List Indicators | |
| ✅ | POST | /api/project/{project_id}/indicators/add |
Project - Add Indicators | add_to_project() |
| ❌ | POST | /api/project/{project_id}/indicators/add_note |
Project - Add Note to Indicators | |
| ❌ | POST | /api/project/{project_id}/indicators/delete |
Project - Delete Indicators | |
| ❌ | POST | /api/project/{project_id}/indicators/tags/add |
Project - Add Tags to Indicators | |
| ❌ | POST | /api/project/{project_id}/indicators/tags/delete |
Project - Delete Tags from Indicators | |
| ❌ | GET | /api/project/{project_id}/scans |
Project - List Scans | |
| ❌ | GET | /api/project/{project_id}/yara/rules |
Project - List Yara Rules | |
| ✅ | GET | /api/project/{project_id}/yara/rules/{rule_id}/matches |
Project - List Matches for YARA rule | yara_matches() |
| Scans | ||||
| ✅ | GET | /api/axon/live/scan/results/{scan_id} |
Live Scan Results | get_scan() |
| ✅ | GET | /api/axon/live/scan/results/{scan_id}/crawl |
Live Scan Results - Crawl | scan(), get_scan_crawl_results() |
| ✅ | POST | /api/axon/live/scan/start |
Live Scan Start | start_scan(), scan() |
| String | ||||
| ✅ | GET | /api/axon/string/dns/extra2 |
String DNS Extra History | extra_history() |
| ✅ | GET | /api/axon/string/dns/history |
String DNS History | dns_history() |
| ❌ | GET | /api/axon/string/pivots2 |
String Pivots | |
| ❌ | GET | /api/axon/string/pivots2/{category} |
String Pivots - Category | |
| ✅ | GET | /api/axon/string/registration/history2 |
String Registration History | registration_history() |
| ❌ | GET | /api/axon/string/registration/history2/{field} |
String Registration History - Category | |
| Threats | ||||
| ❌ | GET | /api/threat/group/{threat_key}/indicators |
Threat Group - List Indicators | |
| ❌ | GET | /api/threat/group/{threat_key}/reports |
Threat Group - List Reports | |
| ❌ | GET | /api/threat/group/{threat_key}/summary |
Threat Group - Summary | |
| ❌ | GET | /api/threat/indicators/recent |
Recent Threat Indicators | |
| ❌ | GET | /api/threat/names |
Threat Names | |
| ❌ | GET | /api/threat/reports/recent |
Recent Threat Reports | |
| Utilities | ||||
| ❌ | GET | /api/axon/advanced/query |
Advanced Query | |
| ❌ | POST | /api/axon/submissions/domains |
Submissions Domains | |
| ❌ | GET | /api/paths |
Paths | |
| ❌ | GET | /api/ping |
Ping | |
| ❌ | GET | /api/profile/token |
Profile Token | |
| ❌ | GET | /api/profile/usage |
Profile Usage | |
| ❌ | GET | /api/profile/usage/daily |
Profile Usage Daily |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file validin_sdk-0.1.0.tar.gz.
File metadata
- Download URL: validin_sdk-0.1.0.tar.gz
- Upload date:
- Size: 32.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
127a80c0f2562f2a4cfd7c1b39eff9c770795bae74239ba1d251bb3e39a472ab
|
|
| MD5 |
1cd23adce1db317445ffb266eab01420
|
|
| BLAKE2b-256 |
c631a04f89eebb7aa58f9b855097aa72b620aaf518e8dfd969166621bdf18111
|
File details
Details for the file validin_sdk-0.1.0-py3-none-any.whl.
File metadata
- Download URL: validin_sdk-0.1.0-py3-none-any.whl
- Upload date:
- Size: 35.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.28 {"installer":{"name":"uv","version":"0.9.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10c71277db05f369553876f4c7bea9b8071215f2811f206944de9ce2d62a0d2e
|
|
| MD5 |
74658f7a02c1ec591bff73e398869f0f
|
|
| BLAKE2b-256 |
a6aeb9ac1a1f921fe4ab20a4cbb7841190b1608611b328e61357312008a0fade
|