billionverify 1.0.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.
- billionverify-1.0.0/.github/workflows/publish.yml +26 -0
- billionverify-1.0.0/.gitignore +39 -0
- billionverify-1.0.0/PKG-INFO +310 -0
- billionverify-1.0.0/README.md +280 -0
- billionverify-1.0.0/billionverify/__init__.py +57 -0
- billionverify-1.0.0/billionverify/client.py +1057 -0
- billionverify-1.0.0/billionverify/exceptions.py +68 -0
- billionverify-1.0.0/billionverify/types.py +141 -0
- billionverify-1.0.0/examples/async_example.py +305 -0
- billionverify-1.0.0/examples/basic.py +189 -0
- billionverify-1.0.0/examples/file_upload.py +312 -0
- billionverify-1.0.0/examples/webhooks.py +329 -0
- billionverify-1.0.0/pyproject.toml +60 -0
- billionverify-1.0.0/pytest.ini +6 -0
- billionverify-1.0.0/tests/__init__.py +1 -0
- billionverify-1.0.0/tests/test_client.py +462 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version: "3.12"
|
|
16
|
+
|
|
17
|
+
- name: Install build tools
|
|
18
|
+
run: pip install build
|
|
19
|
+
|
|
20
|
+
- name: Build package
|
|
21
|
+
run: python -m build
|
|
22
|
+
|
|
23
|
+
- name: Publish to PyPI
|
|
24
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
25
|
+
with:
|
|
26
|
+
password: ${{ secrets.PYPI_TOKEN }}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Virtual environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
|
|
11
|
+
# Distribution / packaging
|
|
12
|
+
dist/
|
|
13
|
+
build/
|
|
14
|
+
*.egg-info/
|
|
15
|
+
*.egg
|
|
16
|
+
|
|
17
|
+
# Test / coverage
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
.tox/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
|
|
24
|
+
# IDE
|
|
25
|
+
.idea/
|
|
26
|
+
.vscode/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
|
|
30
|
+
# OS
|
|
31
|
+
.DS_Store
|
|
32
|
+
Thumbs.db
|
|
33
|
+
|
|
34
|
+
# Environment
|
|
35
|
+
.env
|
|
36
|
+
.env.local
|
|
37
|
+
|
|
38
|
+
# Logs
|
|
39
|
+
*.log
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: billionverify
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official BillionVerify Python SDK for email verification
|
|
5
|
+
Project-URL: Homepage, https://billionverify.com
|
|
6
|
+
Project-URL: Documentation, https://billionverify.com/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/BillionVerify/billionverify-python
|
|
8
|
+
Author-email: BillionVerify <support@billionverify.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Keywords: billionverify,email,email-verification,validation,verification
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.8
|
|
23
|
+
Requires-Dist: httpx>=0.24.0
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
27
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
28
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# billionverify
|
|
32
|
+
|
|
33
|
+
Official BillionVerify Python SDK for email verification.
|
|
34
|
+
|
|
35
|
+
**Documentation:** https://billionverify.com/docs
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install billionverify
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Quick Start
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from billionverify import BillionVerify
|
|
47
|
+
|
|
48
|
+
client = BillionVerify(api_key="your-api-key")
|
|
49
|
+
|
|
50
|
+
# Verify a single email
|
|
51
|
+
result = client.verify("user@example.com")
|
|
52
|
+
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
|
|
53
|
+
print(result.is_deliverable) # True or False
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
client = BillionVerify(
|
|
60
|
+
api_key="your-api-key", # Required
|
|
61
|
+
base_url="https://api.billionverify.com/v1", # Optional
|
|
62
|
+
timeout=30.0, # Optional: Request timeout in seconds (default: 30)
|
|
63
|
+
retries=3, # Optional: Number of retries (default: 3)
|
|
64
|
+
)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Single Email Verification
|
|
68
|
+
|
|
69
|
+
Uses the `/verify/single` endpoint:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
result = client.verify(
|
|
73
|
+
email="user@example.com",
|
|
74
|
+
check_smtp=True, # Optional: Perform SMTP verification (default: True)
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Flat response structure
|
|
78
|
+
print(result.email) # 'user@example.com'
|
|
79
|
+
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
|
|
80
|
+
print(result.score) # 0.95
|
|
81
|
+
print(result.is_deliverable) # True
|
|
82
|
+
print(result.is_disposable) # False
|
|
83
|
+
print(result.is_catchall) # False
|
|
84
|
+
print(result.is_role) # False
|
|
85
|
+
print(result.is_free) # True
|
|
86
|
+
print(result.domain) # 'example.com'
|
|
87
|
+
print(result.reason) # 'Valid email address'
|
|
88
|
+
print(result.smtp_check) # True (whether SMTP was performed)
|
|
89
|
+
print(result.credits_used) # 1
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Bulk Email Verification (Synchronous)
|
|
93
|
+
|
|
94
|
+
Verify up to 50 emails synchronously using `verify_bulk()`:
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
# Synchronous bulk verification (max 50 emails)
|
|
98
|
+
response = client.verify_bulk(
|
|
99
|
+
emails=["user1@example.com", "user2@example.com", "user3@example.com"],
|
|
100
|
+
check_smtp=True, # Optional
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Returns BulkVerifyResponse directly
|
|
104
|
+
print(f"Total: {response.total}")
|
|
105
|
+
print(f"Credits used: {response.credits_used}")
|
|
106
|
+
|
|
107
|
+
for result in response.results:
|
|
108
|
+
print(f"{result.email}: {result.status}")
|
|
109
|
+
print(f" Deliverable: {result.is_deliverable}")
|
|
110
|
+
print(f" Disposable: {result.is_disposable}")
|
|
111
|
+
print(f" Catchall: {result.is_catchall}")
|
|
112
|
+
print(f" Role: {result.is_role}")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## File Upload (Async Verification)
|
|
116
|
+
|
|
117
|
+
For large lists, use `upload_file()` for asynchronous file verification:
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
# Upload a file for async verification
|
|
121
|
+
job = client.upload_file(
|
|
122
|
+
file_path="emails.csv",
|
|
123
|
+
check_smtp=True,
|
|
124
|
+
email_column="email", # Column name for CSV files
|
|
125
|
+
preserve_original=True, # Keep original columns in results
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
print(f"Job ID: {job.job_id}")
|
|
129
|
+
print(f"Status: {job.status}")
|
|
130
|
+
|
|
131
|
+
# Get job status (with optional long-polling)
|
|
132
|
+
status = client.get_file_job_status(
|
|
133
|
+
job_id=job.job_id,
|
|
134
|
+
timeout=60, # Long-poll for up to 60 seconds (0-300)
|
|
135
|
+
)
|
|
136
|
+
print(f"Progress: {status.progress_percent}%")
|
|
137
|
+
|
|
138
|
+
# Wait for completion (polling)
|
|
139
|
+
completed = client.wait_for_file_job(
|
|
140
|
+
job_id=job.job_id,
|
|
141
|
+
poll_interval=5.0, # seconds
|
|
142
|
+
max_wait=600.0, # seconds
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Get results with filter options
|
|
146
|
+
results = client.get_file_job_results(
|
|
147
|
+
job_id=job.job_id,
|
|
148
|
+
limit=100,
|
|
149
|
+
offset=0,
|
|
150
|
+
valid=True, # Include valid emails
|
|
151
|
+
invalid=True, # Include invalid emails
|
|
152
|
+
unknown=True, # Include unknown emails
|
|
153
|
+
risky=True, # Include risky emails
|
|
154
|
+
disposable=True, # Include disposable emails
|
|
155
|
+
catchall=True, # Include catch-all emails
|
|
156
|
+
role=True, # Include role-based emails
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
for item in results.results:
|
|
160
|
+
print(f"{item.email}: {item.status}")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Async Support
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import asyncio
|
|
167
|
+
from billionverify import AsyncBillionVerify
|
|
168
|
+
|
|
169
|
+
async def main():
|
|
170
|
+
async with AsyncBillionVerify(api_key="your-api-key") as client:
|
|
171
|
+
# Single verification
|
|
172
|
+
result = await client.verify("user@example.com")
|
|
173
|
+
print(result.status)
|
|
174
|
+
|
|
175
|
+
# Bulk verification
|
|
176
|
+
response = await client.verify_bulk([
|
|
177
|
+
"user1@example.com",
|
|
178
|
+
"user2@example.com"
|
|
179
|
+
])
|
|
180
|
+
for r in response.results:
|
|
181
|
+
print(f"{r.email}: {r.status}")
|
|
182
|
+
|
|
183
|
+
asyncio.run(main())
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Health Check
|
|
187
|
+
|
|
188
|
+
Check API health status (no authentication required):
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
health = client.health_check()
|
|
192
|
+
print(health.status) # 'ok'
|
|
193
|
+
print(health.version) # API version
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Credits
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
credits = client.get_credits()
|
|
200
|
+
print(credits.credits_balance) # Available credits
|
|
201
|
+
print(credits.credits_consumed) # Credits used
|
|
202
|
+
print(credits.credits_added) # Total credits added
|
|
203
|
+
print(credits.api_key_name) # API key name
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Webhooks
|
|
207
|
+
|
|
208
|
+
Webhooks support events: `file.completed`, `file.failed`
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
# Create a webhook
|
|
212
|
+
webhook = client.create_webhook(
|
|
213
|
+
url="https://your-app.com/webhooks/billionverify",
|
|
214
|
+
events=["file.completed", "file.failed"],
|
|
215
|
+
)
|
|
216
|
+
print(f"Webhook ID: {webhook.id}")
|
|
217
|
+
print(f"Secret: {webhook.secret}") # Save this for signature verification
|
|
218
|
+
|
|
219
|
+
# List webhooks
|
|
220
|
+
webhooks = client.list_webhooks()
|
|
221
|
+
for wh in webhooks:
|
|
222
|
+
print(f"{wh.id}: {wh.url}")
|
|
223
|
+
|
|
224
|
+
# Delete a webhook
|
|
225
|
+
client.delete_webhook(webhook.id)
|
|
226
|
+
|
|
227
|
+
# Verify webhook signature
|
|
228
|
+
from billionverify import BillionVerify
|
|
229
|
+
|
|
230
|
+
is_valid = BillionVerify.verify_webhook_signature(
|
|
231
|
+
payload=raw_body,
|
|
232
|
+
signature=signature_header,
|
|
233
|
+
secret="your-webhook-secret",
|
|
234
|
+
)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## Error Handling
|
|
238
|
+
|
|
239
|
+
```python
|
|
240
|
+
from billionverify import (
|
|
241
|
+
BillionVerify,
|
|
242
|
+
AuthenticationError,
|
|
243
|
+
RateLimitError,
|
|
244
|
+
ValidationError,
|
|
245
|
+
InsufficientCreditsError,
|
|
246
|
+
NotFoundError,
|
|
247
|
+
TimeoutError,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
result = client.verify("user@example.com")
|
|
252
|
+
except AuthenticationError:
|
|
253
|
+
print("Invalid API key")
|
|
254
|
+
except RateLimitError as e:
|
|
255
|
+
print(f"Rate limited. Retry after {e.retry_after} seconds")
|
|
256
|
+
except ValidationError as e:
|
|
257
|
+
print(f"Invalid input: {e.message}")
|
|
258
|
+
except InsufficientCreditsError:
|
|
259
|
+
print("Not enough credits")
|
|
260
|
+
except NotFoundError:
|
|
261
|
+
print("Resource not found")
|
|
262
|
+
except TimeoutError:
|
|
263
|
+
print("Request timed out")
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Context Manager
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
with BillionVerify(api_key="your-api-key") as client:
|
|
270
|
+
result = client.verify("user@example.com")
|
|
271
|
+
print(result.status)
|
|
272
|
+
# Connection is automatically closed
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Type Hints
|
|
276
|
+
|
|
277
|
+
This SDK includes full type annotations for IDE support and type checking.
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
from billionverify import (
|
|
281
|
+
VerificationResult,
|
|
282
|
+
BulkVerifyResponse,
|
|
283
|
+
FileJobResponse,
|
|
284
|
+
CreditsResponse,
|
|
285
|
+
VerificationStatus,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
def process_result(result: VerificationResult) -> None:
|
|
289
|
+
if result.status == "valid":
|
|
290
|
+
print(f"Email {result.email} is valid")
|
|
291
|
+
|
|
292
|
+
if result.is_deliverable and not result.is_disposable:
|
|
293
|
+
print("Safe to send to this email")
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
## Status Values
|
|
297
|
+
|
|
298
|
+
The verification status can be one of:
|
|
299
|
+
|
|
300
|
+
- `valid` - Email is valid and deliverable
|
|
301
|
+
- `invalid` - Email is invalid or does not exist
|
|
302
|
+
- `unknown` - Could not determine status
|
|
303
|
+
- `risky` - Email exists but may have delivery issues
|
|
304
|
+
- `disposable` - Temporary/disposable email address
|
|
305
|
+
- `catchall` - Domain accepts all emails (catch-all)
|
|
306
|
+
- `role` - Role-based email (e.g., info@, support@)
|
|
307
|
+
|
|
308
|
+
## License
|
|
309
|
+
|
|
310
|
+
MIT
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# billionverify
|
|
2
|
+
|
|
3
|
+
Official BillionVerify Python SDK for email verification.
|
|
4
|
+
|
|
5
|
+
**Documentation:** https://billionverify.com/docs
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install billionverify
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
from billionverify import BillionVerify
|
|
17
|
+
|
|
18
|
+
client = BillionVerify(api_key="your-api-key")
|
|
19
|
+
|
|
20
|
+
# Verify a single email
|
|
21
|
+
result = client.verify("user@example.com")
|
|
22
|
+
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
|
|
23
|
+
print(result.is_deliverable) # True or False
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
client = BillionVerify(
|
|
30
|
+
api_key="your-api-key", # Required
|
|
31
|
+
base_url="https://api.billionverify.com/v1", # Optional
|
|
32
|
+
timeout=30.0, # Optional: Request timeout in seconds (default: 30)
|
|
33
|
+
retries=3, # Optional: Number of retries (default: 3)
|
|
34
|
+
)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Single Email Verification
|
|
38
|
+
|
|
39
|
+
Uses the `/verify/single` endpoint:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
result = client.verify(
|
|
43
|
+
email="user@example.com",
|
|
44
|
+
check_smtp=True, # Optional: Perform SMTP verification (default: True)
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# Flat response structure
|
|
48
|
+
print(result.email) # 'user@example.com'
|
|
49
|
+
print(result.status) # 'valid', 'invalid', 'unknown', 'risky', 'disposable', 'catchall', 'role'
|
|
50
|
+
print(result.score) # 0.95
|
|
51
|
+
print(result.is_deliverable) # True
|
|
52
|
+
print(result.is_disposable) # False
|
|
53
|
+
print(result.is_catchall) # False
|
|
54
|
+
print(result.is_role) # False
|
|
55
|
+
print(result.is_free) # True
|
|
56
|
+
print(result.domain) # 'example.com'
|
|
57
|
+
print(result.reason) # 'Valid email address'
|
|
58
|
+
print(result.smtp_check) # True (whether SMTP was performed)
|
|
59
|
+
print(result.credits_used) # 1
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Bulk Email Verification (Synchronous)
|
|
63
|
+
|
|
64
|
+
Verify up to 50 emails synchronously using `verify_bulk()`:
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# Synchronous bulk verification (max 50 emails)
|
|
68
|
+
response = client.verify_bulk(
|
|
69
|
+
emails=["user1@example.com", "user2@example.com", "user3@example.com"],
|
|
70
|
+
check_smtp=True, # Optional
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Returns BulkVerifyResponse directly
|
|
74
|
+
print(f"Total: {response.total}")
|
|
75
|
+
print(f"Credits used: {response.credits_used}")
|
|
76
|
+
|
|
77
|
+
for result in response.results:
|
|
78
|
+
print(f"{result.email}: {result.status}")
|
|
79
|
+
print(f" Deliverable: {result.is_deliverable}")
|
|
80
|
+
print(f" Disposable: {result.is_disposable}")
|
|
81
|
+
print(f" Catchall: {result.is_catchall}")
|
|
82
|
+
print(f" Role: {result.is_role}")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## File Upload (Async Verification)
|
|
86
|
+
|
|
87
|
+
For large lists, use `upload_file()` for asynchronous file verification:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# Upload a file for async verification
|
|
91
|
+
job = client.upload_file(
|
|
92
|
+
file_path="emails.csv",
|
|
93
|
+
check_smtp=True,
|
|
94
|
+
email_column="email", # Column name for CSV files
|
|
95
|
+
preserve_original=True, # Keep original columns in results
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
print(f"Job ID: {job.job_id}")
|
|
99
|
+
print(f"Status: {job.status}")
|
|
100
|
+
|
|
101
|
+
# Get job status (with optional long-polling)
|
|
102
|
+
status = client.get_file_job_status(
|
|
103
|
+
job_id=job.job_id,
|
|
104
|
+
timeout=60, # Long-poll for up to 60 seconds (0-300)
|
|
105
|
+
)
|
|
106
|
+
print(f"Progress: {status.progress_percent}%")
|
|
107
|
+
|
|
108
|
+
# Wait for completion (polling)
|
|
109
|
+
completed = client.wait_for_file_job(
|
|
110
|
+
job_id=job.job_id,
|
|
111
|
+
poll_interval=5.0, # seconds
|
|
112
|
+
max_wait=600.0, # seconds
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Get results with filter options
|
|
116
|
+
results = client.get_file_job_results(
|
|
117
|
+
job_id=job.job_id,
|
|
118
|
+
limit=100,
|
|
119
|
+
offset=0,
|
|
120
|
+
valid=True, # Include valid emails
|
|
121
|
+
invalid=True, # Include invalid emails
|
|
122
|
+
unknown=True, # Include unknown emails
|
|
123
|
+
risky=True, # Include risky emails
|
|
124
|
+
disposable=True, # Include disposable emails
|
|
125
|
+
catchall=True, # Include catch-all emails
|
|
126
|
+
role=True, # Include role-based emails
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
for item in results.results:
|
|
130
|
+
print(f"{item.email}: {item.status}")
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Async Support
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
import asyncio
|
|
137
|
+
from billionverify import AsyncBillionVerify
|
|
138
|
+
|
|
139
|
+
async def main():
|
|
140
|
+
async with AsyncBillionVerify(api_key="your-api-key") as client:
|
|
141
|
+
# Single verification
|
|
142
|
+
result = await client.verify("user@example.com")
|
|
143
|
+
print(result.status)
|
|
144
|
+
|
|
145
|
+
# Bulk verification
|
|
146
|
+
response = await client.verify_bulk([
|
|
147
|
+
"user1@example.com",
|
|
148
|
+
"user2@example.com"
|
|
149
|
+
])
|
|
150
|
+
for r in response.results:
|
|
151
|
+
print(f"{r.email}: {r.status}")
|
|
152
|
+
|
|
153
|
+
asyncio.run(main())
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Health Check
|
|
157
|
+
|
|
158
|
+
Check API health status (no authentication required):
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
health = client.health_check()
|
|
162
|
+
print(health.status) # 'ok'
|
|
163
|
+
print(health.version) # API version
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Credits
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
credits = client.get_credits()
|
|
170
|
+
print(credits.credits_balance) # Available credits
|
|
171
|
+
print(credits.credits_consumed) # Credits used
|
|
172
|
+
print(credits.credits_added) # Total credits added
|
|
173
|
+
print(credits.api_key_name) # API key name
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Webhooks
|
|
177
|
+
|
|
178
|
+
Webhooks support events: `file.completed`, `file.failed`
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
# Create a webhook
|
|
182
|
+
webhook = client.create_webhook(
|
|
183
|
+
url="https://your-app.com/webhooks/billionverify",
|
|
184
|
+
events=["file.completed", "file.failed"],
|
|
185
|
+
)
|
|
186
|
+
print(f"Webhook ID: {webhook.id}")
|
|
187
|
+
print(f"Secret: {webhook.secret}") # Save this for signature verification
|
|
188
|
+
|
|
189
|
+
# List webhooks
|
|
190
|
+
webhooks = client.list_webhooks()
|
|
191
|
+
for wh in webhooks:
|
|
192
|
+
print(f"{wh.id}: {wh.url}")
|
|
193
|
+
|
|
194
|
+
# Delete a webhook
|
|
195
|
+
client.delete_webhook(webhook.id)
|
|
196
|
+
|
|
197
|
+
# Verify webhook signature
|
|
198
|
+
from billionverify import BillionVerify
|
|
199
|
+
|
|
200
|
+
is_valid = BillionVerify.verify_webhook_signature(
|
|
201
|
+
payload=raw_body,
|
|
202
|
+
signature=signature_header,
|
|
203
|
+
secret="your-webhook-secret",
|
|
204
|
+
)
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Error Handling
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
from billionverify import (
|
|
211
|
+
BillionVerify,
|
|
212
|
+
AuthenticationError,
|
|
213
|
+
RateLimitError,
|
|
214
|
+
ValidationError,
|
|
215
|
+
InsufficientCreditsError,
|
|
216
|
+
NotFoundError,
|
|
217
|
+
TimeoutError,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
result = client.verify("user@example.com")
|
|
222
|
+
except AuthenticationError:
|
|
223
|
+
print("Invalid API key")
|
|
224
|
+
except RateLimitError as e:
|
|
225
|
+
print(f"Rate limited. Retry after {e.retry_after} seconds")
|
|
226
|
+
except ValidationError as e:
|
|
227
|
+
print(f"Invalid input: {e.message}")
|
|
228
|
+
except InsufficientCreditsError:
|
|
229
|
+
print("Not enough credits")
|
|
230
|
+
except NotFoundError:
|
|
231
|
+
print("Resource not found")
|
|
232
|
+
except TimeoutError:
|
|
233
|
+
print("Request timed out")
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Context Manager
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
with BillionVerify(api_key="your-api-key") as client:
|
|
240
|
+
result = client.verify("user@example.com")
|
|
241
|
+
print(result.status)
|
|
242
|
+
# Connection is automatically closed
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Type Hints
|
|
246
|
+
|
|
247
|
+
This SDK includes full type annotations for IDE support and type checking.
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
from billionverify import (
|
|
251
|
+
VerificationResult,
|
|
252
|
+
BulkVerifyResponse,
|
|
253
|
+
FileJobResponse,
|
|
254
|
+
CreditsResponse,
|
|
255
|
+
VerificationStatus,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
def process_result(result: VerificationResult) -> None:
|
|
259
|
+
if result.status == "valid":
|
|
260
|
+
print(f"Email {result.email} is valid")
|
|
261
|
+
|
|
262
|
+
if result.is_deliverable and not result.is_disposable:
|
|
263
|
+
print("Safe to send to this email")
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Status Values
|
|
267
|
+
|
|
268
|
+
The verification status can be one of:
|
|
269
|
+
|
|
270
|
+
- `valid` - Email is valid and deliverable
|
|
271
|
+
- `invalid` - Email is invalid or does not exist
|
|
272
|
+
- `unknown` - Could not determine status
|
|
273
|
+
- `risky` - Email exists but may have delivery issues
|
|
274
|
+
- `disposable` - Temporary/disposable email address
|
|
275
|
+
- `catchall` - Domain accepts all emails (catch-all)
|
|
276
|
+
- `role` - Role-based email (e.g., info@, support@)
|
|
277
|
+
|
|
278
|
+
## License
|
|
279
|
+
|
|
280
|
+
MIT
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""BillionVerify Python SDK for email verification."""
|
|
2
|
+
|
|
3
|
+
from .client import AsyncBillionVerify, BillionVerify
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
BillionVerifyError,
|
|
7
|
+
InsufficientCreditsError,
|
|
8
|
+
NotFoundError,
|
|
9
|
+
RateLimitError,
|
|
10
|
+
TimeoutError,
|
|
11
|
+
ValidationError,
|
|
12
|
+
)
|
|
13
|
+
from .types import (
|
|
14
|
+
BulkVerificationResult,
|
|
15
|
+
BulkVerifyResponse,
|
|
16
|
+
CreditsResponse,
|
|
17
|
+
DomainReputation,
|
|
18
|
+
FileJobResponse,
|
|
19
|
+
FileResultItem,
|
|
20
|
+
FileResultsResponse,
|
|
21
|
+
HealthCheckResponse,
|
|
22
|
+
JobStatus,
|
|
23
|
+
VerificationResult,
|
|
24
|
+
VerificationStatus,
|
|
25
|
+
Webhook,
|
|
26
|
+
WebhookEvent,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
__version__ = "1.0.0"
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
# Clients
|
|
33
|
+
"BillionVerify",
|
|
34
|
+
"AsyncBillionVerify",
|
|
35
|
+
# Types
|
|
36
|
+
"VerificationResult",
|
|
37
|
+
"VerificationStatus",
|
|
38
|
+
"BulkVerificationResult",
|
|
39
|
+
"BulkVerifyResponse",
|
|
40
|
+
"FileJobResponse",
|
|
41
|
+
"FileResultItem",
|
|
42
|
+
"FileResultsResponse",
|
|
43
|
+
"CreditsResponse",
|
|
44
|
+
"HealthCheckResponse",
|
|
45
|
+
"DomainReputation",
|
|
46
|
+
"JobStatus",
|
|
47
|
+
"Webhook",
|
|
48
|
+
"WebhookEvent",
|
|
49
|
+
# Exceptions
|
|
50
|
+
"BillionVerifyError",
|
|
51
|
+
"AuthenticationError",
|
|
52
|
+
"RateLimitError",
|
|
53
|
+
"ValidationError",
|
|
54
|
+
"InsufficientCreditsError",
|
|
55
|
+
"NotFoundError",
|
|
56
|
+
"TimeoutError",
|
|
57
|
+
]
|