validin-sdk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- validin_sdk-0.1.0/LICENSE +21 -0
- validin_sdk-0.1.0/PKG-INFO +516 -0
- validin_sdk-0.1.0/README.md +500 -0
- validin_sdk-0.1.0/pyproject.toml +31 -0
- validin_sdk-0.1.0/setup.cfg +4 -0
- validin_sdk-0.1.0/src/validin/__init__.py +47 -0
- validin_sdk-0.1.0/src/validin/annotation_record.py +92 -0
- validin_sdk-0.1.0/src/validin/certificate_record.py +217 -0
- validin_sdk-0.1.0/src/validin/client.py +1586 -0
- validin_sdk-0.1.0/src/validin/content.py +140 -0
- validin_sdk-0.1.0/src/validin/dns_record.py +119 -0
- validin_sdk-0.1.0/src/validin/enriched_indicator.py +77 -0
- validin_sdk-0.1.0/src/validin/errors.py +15 -0
- validin_sdk-0.1.0/src/validin/host_response_record.py +348 -0
- validin_sdk-0.1.0/src/validin/indicator.py +115 -0
- validin_sdk-0.1.0/src/validin/lookalike_record.py +99 -0
- validin_sdk-0.1.0/src/validin/registration.py +181 -0
- validin_sdk-0.1.0/src/validin/registration_record.py +116 -0
- validin_sdk-0.1.0/src/validin/result_set.py +181 -0
- validin_sdk-0.1.0/src/validin/scan.py +121 -0
- validin_sdk-0.1.0/src/validin/scan_record.py +159 -0
- validin_sdk-0.1.0/src/validin/yara_match_record.py +189 -0
- validin_sdk-0.1.0/src/validin_sdk.egg-info/PKG-INFO +516 -0
- validin_sdk-0.1.0/src/validin_sdk.egg-info/SOURCES.txt +25 -0
- validin_sdk-0.1.0/src/validin_sdk.egg-info/dependency_links.txt +1 -0
- validin_sdk-0.1.0/src/validin_sdk.egg-info/requires.txt +4 -0
- validin_sdk-0.1.0/src/validin_sdk.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Validin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: validin-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A lightweight Python SDK for the Validin API
|
|
5
|
+
Author-email: Elliot Roe <elliot@validin.com>, Sreekar Madabushi <sreekar@validin.com>
|
|
6
|
+
Classifier: Programming Language :: Python :: 3
|
|
7
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
8
|
+
Classifier: Operating System :: OS Independent
|
|
9
|
+
Requires-Python: >=3.9
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Requires-Dist: requests>=2.31.0
|
|
13
|
+
Provides-Extra: test
|
|
14
|
+
Requires-Dist: pytest>=8.0; extra == "test"
|
|
15
|
+
Dynamic: license-file
|
|
16
|
+
|
|
17
|
+
# Validin Python SDK
|
|
18
|
+
|
|
19
|
+
A Python SDK for the Validin API, designed to enable large-scale monitoring and enrichment workflows.
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Python 3.9+
|
|
24
|
+
- A Validin API key
|
|
25
|
+
|
|
26
|
+
## Installation
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install validin-python-sdk
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from validin import Client
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
The client requires an API key. The simplest approach is to set environment variables:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export VALIDIN_API_KEY="your-api-key"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Enterprise users must also set their endpoint:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
export VALIDIN_BASE_URL="https://your-enterprise-endpoint.example.com"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
You can also pass these directly to the client:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
from validin import Client
|
|
54
|
+
|
|
55
|
+
client = Client(api_key="your-api-key", base_url="https://your-enterprise-endpoint.example.com")
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If `base_url` is not provided, the client defaults to `https://app.validin.com`.
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
Monitor a DNS TXT record query and add new results to a project:
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from validin import Client
|
|
66
|
+
|
|
67
|
+
client = Client()
|
|
68
|
+
|
|
69
|
+
results = client.extra_history("anthropic-domain-verification*", lookback=1)
|
|
70
|
+
client.add_to_project("YOUR_PROJECT_ID", results.values)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For more advanced workflows, see the [`examples/`](examples/) directory.
|
|
74
|
+
|
|
75
|
+
## Core Concepts
|
|
76
|
+
|
|
77
|
+
### Indicators
|
|
78
|
+
|
|
79
|
+
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:
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
client.dns_history("example.com") # inferred as domain
|
|
83
|
+
client.dns_history("1.1.1.1") # inferred as IP
|
|
84
|
+
client.extra_history("some-txt-value*") # inferred as string (wildcard)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### ResultSet
|
|
88
|
+
|
|
89
|
+
A `ResultSet` is the container returned by every query method. It provides:
|
|
90
|
+
|
|
91
|
+
- **Iteration** — loop over individual records (`for record in results`)
|
|
92
|
+
- `.keys` — deduplicated list of `Indicator` objects from each record (the domains/IPs represented)
|
|
93
|
+
- `.keys_str` — string values of `.keys`
|
|
94
|
+
- `.values` — deduplicated list of record values
|
|
95
|
+
- `.to_rows()` — convert all records to a list of dictionaries
|
|
96
|
+
- `.aggregate()` — flatten nested bulk results into a single deduplicated ResultSet
|
|
97
|
+
|
|
98
|
+
### Records
|
|
99
|
+
|
|
100
|
+
Each query method returns a `ResultSet` containing typed record objects. Available record types:
|
|
101
|
+
|
|
102
|
+
- `DNSRecord`
|
|
103
|
+
- `CertificateRecord`
|
|
104
|
+
- `HostResponseRecord`
|
|
105
|
+
- `ScanRecord`
|
|
106
|
+
- `EnrichedIndicator` (from reputation lookups)
|
|
107
|
+
- `AnnotationRecord` (nested inside `EnrichedIndicator`)
|
|
108
|
+
- `LookalikeRecord`
|
|
109
|
+
- `RegistrationRecord`
|
|
110
|
+
- `YaraMatchRecord`
|
|
111
|
+
- `Content`
|
|
112
|
+
|
|
113
|
+
### Enriched Indicators
|
|
114
|
+
|
|
115
|
+
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:
|
|
116
|
+
|
|
117
|
+
**1. Enrichment lookups** — `client.enrich()` returns a `ResultSet` where each record is an `EnrichedIndicator` with `score`, `verdict`, and `annotations`:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
results = client.enrich("example.com")
|
|
121
|
+
enriched = results[0]
|
|
122
|
+
|
|
123
|
+
print(enriched.value) # "example.com"
|
|
124
|
+
print(enriched.score) # 0
|
|
125
|
+
print(enriched.verdict) # "benign"
|
|
126
|
+
print(enriched.annotations) # tuple of AnnotationRecord objects
|
|
127
|
+
print(enriched.to_rows()) # annotations flattened to list of dicts
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
For bulk enrichment, use `.keys` to iterate the `EnrichedIndicator` objects:
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
results = client.enrich(["example.com", "1.1.1.1", "google.com"])
|
|
134
|
+
for enriched in results.keys:
|
|
135
|
+
print(f"{enriched.value}: score={enriched.score}, verdict={enriched.verdict}")
|
|
136
|
+
print(enriched.to_rows())
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
**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:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
results = client.dns_history("example.com", annotate=True)
|
|
143
|
+
for record in results:
|
|
144
|
+
if isinstance(record.value, EnrichedIndicator):
|
|
145
|
+
print(f"{record.value.value} has {len(record.value.annotations)} annotations")
|
|
146
|
+
print(record.value.informational)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
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.
|
|
150
|
+
|
|
151
|
+
### Bulk Queries and Aggregation
|
|
152
|
+
|
|
153
|
+
Any method that supports bulk queries can also accept a list of indicators instead of a single value:
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
results = client.enrich(["example.com", "1.1.1.1", "google.com"])
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
When you pass a list, the SDK:
|
|
160
|
+
|
|
161
|
+
- Rate-limits requests to 5 queries/second
|
|
162
|
+
- Retries transient failures (408, 429, 500, 502, 503, 504) with exponential backoff
|
|
163
|
+
- Silently skips 404 responses
|
|
164
|
+
|
|
165
|
+
The returned `ResultSet` contains one child `ResultSet` per indicator. To flatten all results into a single deduplicated list, call `.aggregate()`:
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
results = client.dns_history(["example.com", "google.com", "cloudflare.com"])
|
|
169
|
+
|
|
170
|
+
# Iterate per-indicator results
|
|
171
|
+
for child_result_set in results:
|
|
172
|
+
print(child_result_set.query_key, len(child_result_set))
|
|
173
|
+
|
|
174
|
+
# Or flatten into one deduplicated set
|
|
175
|
+
all_records = results.aggregate()
|
|
176
|
+
print(all_records.to_rows())
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Available Methods
|
|
180
|
+
|
|
181
|
+
### `client.dns_history(indicator)`
|
|
182
|
+
|
|
183
|
+
DNS record history for a domain, IP, or string.
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
| Indicator Type | API Route |
|
|
187
|
+
| -------------- | -------------------------------------- |
|
|
188
|
+
| Domain | `/api/axon/domain/dns/history/:domain` |
|
|
189
|
+
| IP | `/api/axon/ip/dns/history/:ip` |
|
|
190
|
+
| String | `/api/axon/string/dns/history` |
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
Supports bulk queries. Options: `limit`, `first_seen`, `last_seen`, `lookback`, `annotate`, `wildcard`, `categories_include`, `exclude_nx`.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
### `client.extra_history(indicator)`
|
|
198
|
+
|
|
199
|
+
Extended DNS record history (TXT, SPF, etc.) for a domain, IP, or string.
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
| Indicator Type | API Route |
|
|
203
|
+
| -------------- | ------------------------------------ |
|
|
204
|
+
| Domain | `/api/axon/domain/dns/extra/:domain` |
|
|
205
|
+
| IP | `/api/axon/ip/dns/extra/:ip` |
|
|
206
|
+
| String | `/api/axon/string/dns/extra2` |
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
Supports bulk queries. Options: `limit`, `first_seen`, `last_seen`, `lookback`, `annotate`, `wildcard`, `categories_include`, `exclude_nx`.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### `client.host_responses(indicator)`
|
|
214
|
+
|
|
215
|
+
HTTP crawl/response history for a domain, IP, hash, or string.
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
| Indicator Type | API Route |
|
|
219
|
+
| -------------- | ---------------------------------------- |
|
|
220
|
+
| Domain | `/api/axon/domain/crawl/history/:domain` |
|
|
221
|
+
| IP | `/api/axon/ip/crawl/history/:ip` |
|
|
222
|
+
| Hash | `/api/axon/hash/crawl/history/:hash` |
|
|
223
|
+
| String | `/api/axon/string/crawl/history` |
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
Supports bulk queries. Options: `limit`, `lookback`, `annotate`.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
### `client.enrich(indicator)`
|
|
231
|
+
|
|
232
|
+
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.
|
|
233
|
+
|
|
234
|
+
Also available as `client.reputation()` (alias).
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
| Indicator Type | API Route |
|
|
238
|
+
| -------------- | ------------------------------------------- |
|
|
239
|
+
| Domain | `/api/axon/domain/reputation/quick/:domain` |
|
|
240
|
+
| IP | `/api/axon/ip/reputation/quick/:ip` |
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
Supports bulk queries. No additional options.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### `client.lookalikes(target)`
|
|
248
|
+
|
|
249
|
+
Find newly registered lookalike domains matching a domain or regex pattern.
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
| Target Type | API Route |
|
|
253
|
+
| ----------- | ------------------------------- |
|
|
254
|
+
| Domain | `/api/lookalike/domain/:domain` |
|
|
255
|
+
| Regex | `/api/lookalike/regex` |
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
Does not support bulk queries. Options: `exclude`, `limit` (1–250), `lookback` (1–90 days), `depth` (`labels`, `subdomains`, `fqdns`), `similarity` (0–4, domain targets only).
|
|
259
|
+
|
|
260
|
+
Regex targets can be passed as a compiled `re.Pattern` or a slash-delimited string:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
client.lookalikes("/^(t-mobile|att|verizon)\.([a-z]{5,6})\.(icu|cc)$/")
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### `client.certificates(indicator)`
|
|
269
|
+
|
|
270
|
+
Historic certificate transparency matches for a domain.
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
| Indicator Type | API Route |
|
|
274
|
+
| -------------- | -------------------------------------- |
|
|
275
|
+
| Domain | `/api/axon/domain/certificates/:domain` |
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
Does not support bulk queries. Options: `wildcard`, `limit` (1–20000), `first_seen`, `last_seen`, `lookback`, `time_format` (`unix` or `iso`).
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
### `client.ptr_history(indicator)`
|
|
283
|
+
|
|
284
|
+
Historic PTR/hostname records for a domain or IP.
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
| Indicator Type | API Route |
|
|
288
|
+
| -------------- | -------------------------------------- |
|
|
289
|
+
| Domain | `/api/axon/domain/dns/hostname/:domain` |
|
|
290
|
+
| IP | `/api/axon/ip/dns/hostname/:ip` |
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
Supports bulk queries. Options: `limit`, `first_seen`, `last_seen`, `lookback`, `annotate`, `time_format` (`unix` or `iso`), and `wildcard` for domain queries only.
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
### `client.start_scan(find)`
|
|
298
|
+
|
|
299
|
+
Start an enterprise live HTTP/S scan and return a `ScanJob`.
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
| API Route |
|
|
303
|
+
| ----------------------------- |
|
|
304
|
+
| `/api/axon/live/scan/start` |
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
Does not support bulk queries. Options: `countries`, `refer`, `user_agent`.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
### `client.get_scan(scan_id)`
|
|
312
|
+
|
|
313
|
+
Fetch live scan status and return a `ScanJob`.
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
| API Route |
|
|
317
|
+
| ------------------------------------------ |
|
|
318
|
+
| `/api/axon/live/scan/results/:scan_id` |
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
Does not support bulk queries.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
### `client.scan(find)`
|
|
326
|
+
|
|
327
|
+
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.
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
| API Route |
|
|
331
|
+
| ----------------------------------------------------- |
|
|
332
|
+
| `/api/axon/live/scan/start` -> poll results -> crawl |
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
Options: `countries`, `refer`, `user_agent`, `wait`, `poll_interval`, `timeout`.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### `client.registration_history(indicator)`
|
|
340
|
+
|
|
341
|
+
WHOIS/RDAP registration history for a domain or string.
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
| Indicator Type | API Route |
|
|
345
|
+
| -------------- | ----------------------------------------------- |
|
|
346
|
+
| Domain | `/api/axon/domain/registration/history/:domain` |
|
|
347
|
+
| String | `/api/axon/string/registration/history2` |
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
Supports bulk queries. Options: `limit`, `first_seen`, `last_seen`, `lookback`, `annotate`, `wildcard`, `include_fields`.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
### `client.yara_matches(project_id, rule_id)`
|
|
355
|
+
|
|
356
|
+
Fetch YARA rule match results from a project. Auto-paginates all results by default.
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
| API Route |
|
|
360
|
+
| ------------------------------------------------------ |
|
|
361
|
+
| `/api/project/:project_id/yara/rules/:rule_id/matches` |
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
Does not support bulk queries. Options: `page`, `page_size` (provide both for manual pagination), `include_html`, `first_seen`, `last_seen`.
|
|
365
|
+
|
|
366
|
+
---
|
|
367
|
+
|
|
368
|
+
### `client.fetch_content(indicator)`
|
|
369
|
+
|
|
370
|
+
Fetch stored HTML content by body hash.
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
| API Route |
|
|
374
|
+
| ---------------------------------------- |
|
|
375
|
+
| `/api/axon/hash/content/html/sha1/:hash` |
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
Supports bulk queries. Accepts a hash string, `Indicator`, or `HostResponse` object with a `body_hash`.
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
### `client.add_to_project(project_id, indicators)`
|
|
383
|
+
|
|
384
|
+
Add indicators to a Validin project.
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
| API Route |
|
|
388
|
+
| ----------------------------------------- |
|
|
389
|
+
| `/api/project/:project_id/indicators/add` |
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
Accepts a single indicator or a list. Options: `note`, `tags`.
|
|
393
|
+
|
|
394
|
+
## Examples
|
|
395
|
+
|
|
396
|
+
Example scripts are in the `examples/` directory:
|
|
397
|
+
|
|
398
|
+
- `**lookalike_monitor.py**` — Regex lookalike search for telecom smishing domains, filter by registrar, add to project.
|
|
399
|
+
- `**dns_txt_record_monitor.py**` — Monitor a DNS TXT record wildcard query and add results to a project.
|
|
400
|
+
- `**bulk_indicator_enrichment.py**` — Bulk enrichment lookup across multiple indicators.
|
|
401
|
+
- `**ingest_yara_matches.py**` — Fetch all YARA rule matches for a project and print aggregated results.
|
|
402
|
+
- `**sample_host_responses.py**` — Bulk host response history with HTML content download.
|
|
403
|
+
|
|
404
|
+
## Error Handling
|
|
405
|
+
|
|
406
|
+
The SDK raises `ApiError` for HTTP failures and `ValidinError` as a base exception class:
|
|
407
|
+
|
|
408
|
+
```python
|
|
409
|
+
from validin import Client
|
|
410
|
+
from validin_sdk.errors import ApiError, ValidinError
|
|
411
|
+
|
|
412
|
+
client = Client()
|
|
413
|
+
|
|
414
|
+
try:
|
|
415
|
+
results = client.dns_history("example.com")
|
|
416
|
+
except ApiError as e:
|
|
417
|
+
print(f"HTTP {e.status_code}: {e.message}")
|
|
418
|
+
except ValidinError as e:
|
|
419
|
+
print(f"SDK error: {e}")
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## API Coverage
|
|
423
|
+
|
|
424
|
+
The SDK currently covers **24 of 76** API endpoints.
|
|
425
|
+
|
|
426
|
+
| Status | Method | Endpoint | Summary | SDK Method |
|
|
427
|
+
|:------:|:------:|----------|---------|------------|
|
|
428
|
+
| | | **Bulk** | | |
|
|
429
|
+
| ❌ | POST | `/api/axon/bulk/osint/context` | Bulk OSINT Context | |
|
|
430
|
+
| | | **Domain** | | |
|
|
431
|
+
| ✅ | GET | `/api/axon/domain/certificates/{domain}` | Domain Certificates | `certificates()` |
|
|
432
|
+
| ✅ | GET | `/api/axon/domain/crawl/history/{domain}` | Domain Crawl History | `host_responses()` |
|
|
433
|
+
| ✅ | GET | `/api/axon/domain/dns/extra/{domain}` | Domain DNS Extra | `extra_history()` |
|
|
434
|
+
| ✅ | GET | `/api/axon/domain/dns/history/{domain}` | Domain DNS History | `dns_history()` |
|
|
435
|
+
| ❌ | GET | `/api/axon/domain/dns/history/{domain}/A` | Domain DNS History - A | |
|
|
436
|
+
| ❌ | GET | `/api/axon/domain/dns/history/{domain}/AAAA` | Domain DNS History - AAAA | |
|
|
437
|
+
| ❌ | GET | `/api/axon/domain/dns/history/{domain}/NS` | Domain DNS History - NS | |
|
|
438
|
+
| ❌ | GET | `/api/axon/domain/dns/history/{domain}/NS_FOR` | Domain DNS History - NS_FOR | |
|
|
439
|
+
| ✅ | GET | `/api/axon/domain/dns/hostname/{domain}` | Domain DNS Hostname | `ptr_history()` |
|
|
440
|
+
| ❌ | GET | `/api/axon/domain/osint/history/{domain}` | Domain OSINT History | |
|
|
441
|
+
| ❌ | GET | `/api/axon/domain/pivots/{domain}` | Domain Pivots | |
|
|
442
|
+
| ❌ | GET | `/api/axon/domain/pivots/{domain}/{category}` | Domain Pivots - Category | |
|
|
443
|
+
| ✅ | GET | `/api/axon/domain/registration/history/{domain}` | Domain Registration History | `registration_history()` |
|
|
444
|
+
| ❌ | GET | `/api/axon/domain/registration/live/{domain}` | Domain Registration Live | |
|
|
445
|
+
| ✅ | GET | `/api/axon/domain/reputation/quick/{domain}` | Domain Reputation Quick | `enrich()` |
|
|
446
|
+
| ❌ | GET | `/api/axon/domain/subdomains/{domain}` | Domain Subdomains | |
|
|
447
|
+
| ✅ | GET | `/api/lookalike/domain/{domain}` | Lookalike Domain | `lookalikes()` |
|
|
448
|
+
| ✅ | GET | `/api/lookalike/regex` | Lookalike Regex | `lookalikes()` |
|
|
449
|
+
| ❌ | GET | `/api/v2/domain/combined/connections/{domain}` | V2 Domain Combined Connections | |
|
|
450
|
+
| | | **Hash** | | |
|
|
451
|
+
| ❌ | GET | `/api/axon/hash/content/certificate/sha1/{hash}` | Hash Content Certificate (SHA1) | |
|
|
452
|
+
| ❌ | GET | `/api/axon/hash/content/favicon/md5/{hash}` | Hash Content Favicon (MD5) | |
|
|
453
|
+
| ✅ | GET | `/api/axon/hash/content/html/sha1/{hash}` | Hash Content HTML (SHA1) | `fetch_content()` |
|
|
454
|
+
| ✅ | GET | `/api/axon/hash/crawl/history/{hash}` | Hash Crawl History | `host_responses()` |
|
|
455
|
+
| ❌ | GET | `/api/axon/hash/pivots/{hash}` | Hash Pivots | |
|
|
456
|
+
| ❌ | GET | `/api/axon/hash/pivots/{hash}/{category}` | Hash Pivots - Category | |
|
|
457
|
+
| | | **IP** | | |
|
|
458
|
+
| ✅ | GET | `/api/axon/ip/crawl/history/{ip}` | IP Crawl History | `host_responses()` |
|
|
459
|
+
| ❌ | GET | `/api/axon/ip/crawl/history/{ip}/{cidr}` | IP Crawl History - (CIDR) | |
|
|
460
|
+
| ✅ | GET | `/api/axon/ip/dns/extra/{ip}` | IP DNS Extra | `extra_history()` |
|
|
461
|
+
| ❌ | GET | `/api/axon/ip/dns/extra/{ip}/{cidr}` | IP DNS Extra - (CIDR) | |
|
|
462
|
+
| ✅ | GET | `/api/axon/ip/dns/history/{ip}` | IP DNS History | `dns_history()` |
|
|
463
|
+
| ❌ | GET | `/api/axon/ip/dns/history/{ip}/{cidr}` | IP DNS History - (CIDR) | |
|
|
464
|
+
| ✅ | GET | `/api/axon/ip/dns/hostname/{ip}` | IP DNS Hostname | `ptr_history()` |
|
|
465
|
+
| ❌ | GET | `/api/axon/ip/dns/hostname/{ip}/{cidr}` | IP DNS Hostname - (CIDR) | |
|
|
466
|
+
| ❌ | GET | `/api/axon/ip/osint/history/{ip}` | IP OSINT History | |
|
|
467
|
+
| ❌ | GET | `/api/axon/ip/osint/history/{ip}/{cidr}` | IP OSINT History - (CIDR) | |
|
|
468
|
+
| ❌ | GET | `/api/axon/ip/pivots/{ip}` | IP Pivots | |
|
|
469
|
+
| ❌ | GET | `/api/axon/ip/pivots/{ip}/{cidr}` | IP Pivots - (CIDR) | |
|
|
470
|
+
| ❌ | GET | `/api/axon/ip/pivots2/{ip}/{category}` | IP Pivots - Category | |
|
|
471
|
+
| ✅ | GET | `/api/axon/ip/reputation/quick/{ip}` | IP Reputation Quick | `enrich()` |
|
|
472
|
+
| | | **Projects** | | |
|
|
473
|
+
| ❌ | GET | `/api/project/list` | Project List | |
|
|
474
|
+
| ❌ | GET | `/api/project/{project_id}` | Project Details | |
|
|
475
|
+
| ❌ | GET | `/api/project/{project_id}/alerts/dates` | Project - List Dates that have Alerts | |
|
|
476
|
+
| ❌ | GET | `/api/project/{project_id}/alerts/latest` | Project - Latest Alerts | |
|
|
477
|
+
| ❌ | GET | `/api/project/{project_id}/alerts/{date}` | Project - Alerts for Date | |
|
|
478
|
+
| ❌ | GET | `/api/project/{project_id}/indicators` | Project - List Indicators | |
|
|
479
|
+
| ✅ | POST | `/api/project/{project_id}/indicators/add` | Project - Add Indicators | `add_to_project()` |
|
|
480
|
+
| ❌ | POST | `/api/project/{project_id}/indicators/add_note` | Project - Add Note to Indicators | |
|
|
481
|
+
| ❌ | POST | `/api/project/{project_id}/indicators/delete` | Project - Delete Indicators | |
|
|
482
|
+
| ❌ | POST | `/api/project/{project_id}/indicators/tags/add` | Project - Add Tags to Indicators | |
|
|
483
|
+
| ❌ | POST | `/api/project/{project_id}/indicators/tags/delete` | Project - Delete Tags from Indicators | |
|
|
484
|
+
| ❌ | GET | `/api/project/{project_id}/scans` | Project - List Scans | |
|
|
485
|
+
| ❌ | GET | `/api/project/{project_id}/yara/rules` | Project - List Yara Rules | |
|
|
486
|
+
| ✅ | GET | `/api/project/{project_id}/yara/rules/{rule_id}/matches` | Project - List Matches for YARA rule | `yara_matches()` |
|
|
487
|
+
| | | **Scans** | | |
|
|
488
|
+
| ✅ | GET | `/api/axon/live/scan/results/{scan_id}` | Live Scan Results | `get_scan()` |
|
|
489
|
+
| ✅ | GET | `/api/axon/live/scan/results/{scan_id}/crawl` | Live Scan Results - Crawl | `scan()`, `get_scan_crawl_results()` |
|
|
490
|
+
| ✅ | POST | `/api/axon/live/scan/start` | Live Scan Start | `start_scan()`, `scan()` |
|
|
491
|
+
| | | **String** | | |
|
|
492
|
+
| ✅ | GET | `/api/axon/string/dns/extra2` | String DNS Extra History | `extra_history()` |
|
|
493
|
+
| ✅ | GET | `/api/axon/string/dns/history` | String DNS History | `dns_history()` |
|
|
494
|
+
| ❌ | GET | `/api/axon/string/pivots2` | String Pivots | |
|
|
495
|
+
| ❌ | GET | `/api/axon/string/pivots2/{category}` | String Pivots - Category | |
|
|
496
|
+
| ✅ | GET | `/api/axon/string/registration/history2` | String Registration History | `registration_history()` |
|
|
497
|
+
| ❌ | GET | `/api/axon/string/registration/history2/{field}` | String Registration History - Category | |
|
|
498
|
+
| | | **Threats** | | |
|
|
499
|
+
| ❌ | GET | `/api/threat/group/{threat_key}/indicators` | Threat Group - List Indicators | |
|
|
500
|
+
| ❌ | GET | `/api/threat/group/{threat_key}/reports` | Threat Group - List Reports | |
|
|
501
|
+
| ❌ | GET | `/api/threat/group/{threat_key}/summary` | Threat Group - Summary | |
|
|
502
|
+
| ❌ | GET | `/api/threat/indicators/recent` | Recent Threat Indicators | |
|
|
503
|
+
| ❌ | GET | `/api/threat/names` | Threat Names | |
|
|
504
|
+
| ❌ | GET | `/api/threat/reports/recent` | Recent Threat Reports | |
|
|
505
|
+
| | | **Utilities** | | |
|
|
506
|
+
| ❌ | GET | `/api/axon/advanced/query` | Advanced Query | |
|
|
507
|
+
| ❌ | POST | `/api/axon/submissions/domains` | Submissions Domains | |
|
|
508
|
+
| ❌ | GET | `/api/paths` | Paths | |
|
|
509
|
+
| ❌ | GET | `/api/ping` | Ping | |
|
|
510
|
+
| ❌ | GET | `/api/profile/token` | Profile Token | |
|
|
511
|
+
| ❌ | GET | `/api/profile/usage` | Profile Usage | |
|
|
512
|
+
| ❌ | GET | `/api/profile/usage/daily` | Profile Usage Daily | |
|
|
513
|
+
|
|
514
|
+
## License
|
|
515
|
+
|
|
516
|
+
MIT
|