|
1 | 1 | # ValidKit Python SDK |
2 | 2 |
|
3 | | -[](https://badge.fury.io/py/validkit) |
| 3 | +[](https://pypi.org/project/validkit/) |
4 | 4 | [](https://pypi.org/project/validkit/) |
5 | 5 | [](https://opensource.org/licenses/MIT) |
6 | | -[](https://docs.validkit.com) |
7 | 6 |
|
8 | | -Async Python SDK for ValidKit Email Verification API - Built for AI Agents and high-volume applications. |
9 | | - |
10 | | -## Features |
11 | | - |
12 | | -- 🚀 **Fully Async**: Built on aiohttp for maximum performance |
13 | | -- 🤖 **AI-Agent Optimized**: Token-efficient responses and agent-friendly formats |
14 | | -- 📦 **Batch Processing**: Verify up to 10,000 emails in a single request |
15 | | -- 🔄 **Smart Retries**: Automatic retry logic with exponential backoff |
16 | | -- 🌊 **Connection Pooling**: Efficient connection reuse for high throughput |
17 | | -- 📊 **Progress Tracking**: Real-time progress updates for large batches |
18 | | -- 🪝 **Webhook Support**: Async webhook handling for batch results |
19 | | -- 🔍 **Type Safety**: Full type hints and Pydantic models |
20 | | - |
21 | | -**Full API Documentation**: https://api.validkit.com/docs/openapi.json |
| 7 | +Email validation for signup flows -- block junk without blocking `test+staging@example.com`. Async Python client with batch support up to 10K emails, automatic retries, and Pydantic models. |
22 | 8 |
|
23 | 9 | ## Installation |
24 | 10 |
|
25 | 11 | ```bash |
26 | 12 | pip install validkit |
27 | 13 | ``` |
28 | 14 |
|
| 15 | +Requires Python 3.8+. |
| 16 | + |
29 | 17 | ## Quick Start |
30 | 18 |
|
31 | 19 | ```python |
32 | 20 | import asyncio |
33 | 21 | from validkit import AsyncValidKit |
34 | 22 |
|
35 | 23 | async def main(): |
36 | | - # Initialize the client |
37 | 24 | async with AsyncValidKit(api_key="your_api_key") as client: |
38 | | - # Single email verification |
| 25 | + # Single email |
39 | 26 | result = await client.verify_email("user@example.com") |
40 | | - print(f"Valid: {result.valid}") |
41 | | - |
42 | | - # Batch verification |
43 | | - emails = ["user1@example.com", "user2@example.com", "user3@example.com"] |
44 | | - results = await client.verify_batch(emails) |
45 | | - |
46 | | - for email, result in results.items(): |
47 | | - print(f"{email}: {result.valid}") |
| 27 | + print(result.valid) # True |
48 | 28 |
|
49 | | -asyncio.run(main()) |
50 | | -``` |
| 29 | + # Batch -- compact format by default |
| 30 | + results = await client.verify_batch([ |
| 31 | + "alice@company.com", |
| 32 | + "bob@tempmail.com", |
| 33 | + "not-an-email", |
| 34 | + ]) |
| 35 | + for email, r in results.items(): |
| 36 | + print(f"{email}: valid={r.v}, disposable={r.d}") |
51 | 37 |
|
52 | | -## Advanced Usage |
53 | | - |
54 | | -### Batch Processing with Progress |
55 | | - |
56 | | -```python |
57 | | -async def verify_large_batch(): |
58 | | - async with AsyncValidKit(api_key="your_api_key") as client: |
59 | | - emails = ["email{}@example.com".format(i) for i in range(10000)] |
60 | | - |
61 | | - # Process with progress callback |
62 | | - async def progress_callback(processed, total): |
63 | | - print(f"Progress: {processed}/{total} ({processed/total*100:.1f}%)") |
64 | | - |
65 | | - results = await client.verify_batch( |
66 | | - emails, |
67 | | - chunk_size=1000, |
68 | | - progress_callback=progress_callback |
69 | | - ) |
70 | | - |
71 | | - valid_count = sum(1 for r in results.values() if r.valid) |
72 | | - print(f"Valid emails: {valid_count}/{len(emails)}") |
| 38 | +asyncio.run(main()) |
73 | 39 | ``` |
74 | 40 |
|
75 | | -### Webhook Support |
| 41 | +## Features |
76 | 42 |
|
77 | | -```python |
78 | | -# Start async batch job with webhook |
79 | | -job = await client.verify_batch_async( |
80 | | - emails=large_email_list, |
81 | | - webhook_url="https://your-app.com/webhook/validkit", |
82 | | - webhook_headers={"Authorization": "Bearer your_token"} |
83 | | -) |
| 43 | +- **Async-native** -- aiohttp with connection pooling (100 connections default) |
| 44 | +- **Batch verification** -- up to 10,000 emails per call, chunked automatically |
| 45 | +- **Developer Pattern Intelligence** -- understands `test@`, `+addressing`, disposable domains |
| 46 | +- **Compact format** -- token-efficient responses (`v`, `d`, `r` fields) enabled by default |
| 47 | +- **Streaming** -- `async for` results as they complete |
| 48 | +- **Webhook delivery** -- fire-and-forget async batch jobs with callback |
| 49 | +- **Automatic retries** -- exponential backoff, 3 retries default |
| 50 | +- **Type-safe** -- Pydantic v2 models with full type hints |
84 | 51 |
|
85 | | -print(f"Batch job started: {job.id}") |
86 | | -print(f"Check status at: {job.status_url}") |
87 | | -``` |
| 52 | +## Advanced Usage |
88 | 53 |
|
89 | | -### Custom Configuration |
| 54 | +### Custom configuration |
90 | 55 |
|
91 | 56 | ```python |
92 | 57 | from validkit import AsyncValidKit, ValidKitConfig |
93 | 58 |
|
94 | 59 | config = ValidKitConfig( |
95 | 60 | api_key="your_api_key", |
96 | | - base_url="https://api.validkit.com", |
97 | | - timeout=30, |
98 | | - max_retries=3, |
99 | | - max_connections=100, |
100 | | - rate_limit=10000 # requests per minute |
| 61 | + timeout=30, # seconds |
| 62 | + max_retries=3, # retry count |
| 63 | + max_connections=100, # connection pool size |
| 64 | + rate_limit=10000, # requests/min (None = unlimited) |
| 65 | + compact_format=True, # smaller payloads |
101 | 66 | ) |
102 | 67 |
|
103 | 68 | async with AsyncValidKit(config=config) as client: |
104 | | - # Your code here |
105 | | - pass |
| 69 | + result = await client.verify_email("user@example.com") |
106 | 70 | ``` |
107 | 71 |
|
108 | | -## Response Format |
109 | | - |
110 | | -### Single Email Response |
| 72 | +### Batch with progress tracking |
111 | 73 |
|
112 | 74 | ```python |
113 | | -{ |
114 | | - "valid": true, |
115 | | - "email": "user@example.com", |
116 | | - "format": {"valid": true}, |
117 | | - "disposable": {"valid": true, "value": false}, |
118 | | - "mx": {"valid": true, "records": ["mx1.example.com"]}, |
119 | | - "smtp": {"valid": true} |
120 | | -} |
| 75 | +def on_progress(processed, total): |
| 76 | + print(f"{processed}/{total} ({processed / total * 100:.1f}%)") |
| 77 | + |
| 78 | +results = await client.verify_batch( |
| 79 | + emails, |
| 80 | + chunk_size=1000, |
| 81 | + progress_callback=on_progress, |
| 82 | +) |
121 | 83 | ``` |
122 | 84 |
|
123 | | -### Batch Response (Compact Format) |
| 85 | +### Async batch with webhook |
124 | 86 |
|
125 | 87 | ```python |
126 | | -{ |
127 | | - "user1@example.com": {"v": true, "d": false}, |
128 | | - "user2@example.com": {"v": false, "r": "invalid_format"}, |
129 | | - "user3@example.com": {"v": true, "d": true} |
130 | | -} |
131 | | -``` |
| 88 | +job = await client.verify_batch_async( |
| 89 | + emails=large_list, |
| 90 | + webhook_url="https://your-app.com/webhooks/validkit", |
| 91 | + webhook_headers={"Authorization": "Bearer token"}, |
| 92 | +) |
132 | 93 |
|
133 | | -Where: |
134 | | -- `v`: valid (boolean) |
135 | | -- `d`: disposable (boolean) |
136 | | -- `r`: reason (string, only if invalid) |
| 94 | +# Poll until complete, or wait for webhook |
| 95 | +job = await client.get_batch_status(job.id) |
| 96 | +results = await client.get_batch_results(job.id) |
137 | 97 |
|
138 | | -## Agent-Optimized Features |
| 98 | +# Cancel if needed |
| 99 | +await client.cancel_batch(job.id) |
| 100 | +``` |
139 | 101 |
|
140 | | -### Token-Efficient Mode |
| 102 | +### Streaming |
141 | 103 |
|
142 | 104 | ```python |
143 | | -# Get compact responses (80% smaller) |
144 | | -result = await client.verify_email( |
145 | | - "user@example.com", |
146 | | - format="compact" |
147 | | -) |
| 105 | +async for email, result in client.stream_verify(emails, batch_size=100): |
| 106 | + print(f"{email}: valid={result.v}") |
148 | 107 | ``` |
149 | 108 |
|
150 | | -### Multi-Agent Tracing |
| 109 | +### Trace IDs |
| 110 | + |
| 111 | +Attach a trace ID for cross-service debugging: |
151 | 112 |
|
152 | 113 | ```python |
153 | | -# Include trace headers for multi-agent debugging |
154 | | -result = await client.verify_email( |
155 | | - "user@example.com", |
156 | | - trace_id="agent_123_task_456" |
157 | | -) |
| 114 | +result = await client.verify_email("user@example.com", trace_id="req_abc123") |
158 | 115 | ``` |
159 | 116 |
|
160 | 117 | ## Error Handling |
161 | 118 |
|
162 | 119 | ```python |
163 | 120 | from validkit.exceptions import ( |
164 | | - ValidKitAPIError, |
165 | | - RateLimitError, |
166 | | - InvalidAPIKeyError, |
167 | | - BatchSizeError |
| 121 | + ValidKitError, # base -- catches everything |
| 122 | + ValidKitAPIError, # API errors (4xx, 5xx) |
| 123 | + InvalidAPIKeyError, # 401 |
| 124 | + RateLimitError, # 429, includes retry_after |
| 125 | + BatchSizeError, # batch exceeds 10K |
| 126 | + TimeoutError, # request timeout (inherits ValidKitError, not API) |
| 127 | + ConnectionError, # network failure (inherits ValidKitError, not API) |
168 | 128 | ) |
169 | 129 |
|
170 | 130 | try: |
171 | | - result = await client.verify_email("invalid-email") |
| 131 | + result = await client.verify_email("user@example.com") |
| 132 | +except RateLimitError as e: |
| 133 | + print(e.retry_after) # seconds until retry |
| 134 | +except InvalidAPIKeyError: |
| 135 | + print("Check your API key") |
172 | 136 | except ValidKitAPIError as e: |
173 | | - print(f"API Error: {e.message}") |
174 | | - print(f"Error Code: {e.code}") |
175 | | - print(f"Status Code: {e.status_code}") |
| 137 | + print(e.message, e.status_code, e.code) |
| 138 | +except ValidKitError as e: |
| 139 | + # Catches TimeoutError, ConnectionError, and any other non-API errors |
| 140 | + print(f"SDK error: {e}") |
176 | 141 | ``` |
177 | 142 |
|
178 | | -## Rate Limiting |
| 143 | +The SDK retries automatically on rate limits and transient errors (up to `max_retries`). Catch exceptions only if you need custom handling. |
| 144 | + |
| 145 | +## Compact Response Format |
179 | 146 |
|
180 | | -The SDK automatically handles rate limiting with smart backoff: |
| 147 | +Default format. Smaller payloads, same information: |
| 148 | + |
| 149 | +| Field | Type | Meaning | |
| 150 | +|-------|------|---------| |
| 151 | +| `v` | `bool` | Email is valid | |
| 152 | +| `d` | `bool \| None` | Domain is disposable (None if not checked) | |
| 153 | +| `r` | `str \| None` | Reason (present only when invalid) | |
181 | 154 |
|
182 | 155 | ```python |
183 | | -# SDK will automatically retry with exponential backoff |
184 | | -results = await client.verify_batch( |
185 | | - large_email_list, |
186 | | - auto_retry=True # Default: True |
187 | | -) |
| 156 | +# Compact (default) |
| 157 | +r = await client.verify_email("bad@example.com") |
| 158 | +print(r.v, r.d, r.r) # False, False, "invalid_format" |
| 159 | + |
| 160 | +# Full format -- use when you need MX records, SMTP details |
| 161 | +from validkit.models import ResponseFormat |
| 162 | +full = await client.verify_email("user@example.com", format=ResponseFormat.FULL) |
| 163 | +if full.mx: |
| 164 | + print(full.mx.records) # ["mx1.example.com"] |
188 | 165 | ``` |
189 | 166 |
|
190 | 167 | ## Examples |
191 | 168 |
|
192 | | -Check the `examples/` directory for more detailed examples: |
193 | | - |
194 | | -- `basic_usage.py` - Simple verification examples |
195 | | -- `batch_processing.py` - Large batch processing patterns |
196 | | -- `webhook_handler.py` - Webhook endpoint implementation |
197 | | -- `agent_integration.py` - AI agent integration patterns |
198 | | -- `error_handling.py` - Comprehensive error handling |
199 | | - |
200 | | -## Requirements |
201 | | - |
202 | | -- Python 3.8+ |
203 | | -- aiohttp |
204 | | -- pydantic |
| 169 | +See [`examples/`](examples/): |
205 | 170 |
|
206 | | -## License |
207 | | - |
208 | | -MIT License - see LICENSE file for details. |
209 | | - |
210 | | -## Performance Tips |
211 | | - |
212 | | -1. **Use batch verification** for multiple emails (up to 10,000 per request) |
213 | | -2. **Enable connection pooling** (default) for high-throughput applications |
214 | | -3. **Set appropriate timeouts** based on your batch size |
215 | | -4. **Use webhooks** for large async batches to avoid long-running requests |
| 171 | +- [`basic_usage.py`](examples/basic_usage.py) -- single verification, batch, streaming, configuration |
| 172 | +- [`batch_processing.py`](examples/batch_processing.py) -- large batches, CSV processing, webhook jobs, domain analysis |
216 | 173 |
|
217 | 174 | ## Contributing |
218 | 175 |
|
219 | | -We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details. |
220 | | - |
221 | | -### Development Setup |
222 | | - |
223 | | -```bash |
224 | | -# Clone the repository |
225 | | -git clone https://github.com/ValidKit/validkit-python-sdk.git |
226 | | -cd validkit-python-sdk |
227 | | - |
228 | | -# Create virtual environment |
229 | | -python -m venv venv |
230 | | -source venv/bin/activate # On Windows: venv\Scripts\activate |
231 | | - |
232 | | -# Install dependencies |
233 | | -pip install -e ".[dev]" |
234 | | - |
235 | | -# Run tests |
236 | | -pytest |
237 | | -``` |
| 176 | +See [CONTRIBUTING.md](CONTRIBUTING.md). |
238 | 177 |
|
239 | 178 | ## Support |
240 | 179 |
|
241 | | -- 📖 **Documentation**: https://docs.validkit.com |
242 | | -- 🔧 **API Reference**: https://api.validkit.com/docs/openapi.json |
243 | | -- 🐛 **Issues**: https://github.com/ValidKit/validkit-python-sdk/issues |
244 | | -- 📧 **Email**: support@validkit.com |
245 | | -- 💬 **Discord**: [Join our community](https://discord.gg/validkit) |
| 180 | +[Docs](https://docs.validkit.com) -- [GitHub Issues](https://github.com/ValidKit/validkit-python-sdk/issues) -- support@validkit.com |
246 | 181 |
|
247 | | ---- |
| 182 | +## License |
248 | 183 |
|
249 | | -Built with ❤️ for AI agents by [ValidKit](https://validkit.com) |
| 184 | +MIT -- see [LICENSE](LICENSE). |
0 commit comments