Metadata-Version: 2.4
Name: verifly-email
Version: 1.0.0
Summary: Official Python SDK for the Verifly email-verification API (verifly.email)
Author: Verifly
License: MIT
Project-URL: Homepage, https://verifly.email
Project-URL: Documentation, https://verifly.email/docs/api
Project-URL: API Spec, https://verifly.email/openapi.json
Keywords: email,verification,validation,verifly,deliverability
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"

# verifly-email (Python)

Official Python SDK for the [Verifly](https://verifly.email) email-verification API.

> **Package naming.** Install **`verifly-email`** and import **`verifly_email`**.
> The plain name `verifly` on PyPI belongs to an **unrelated 2FA company** — it
> is *not* this project. Always use `verifly-email`.

- Zero dependencies (pure Python standard library).
- Fully typed, with docstrings on every method.
- Built-in retry with backoff on `429` / `5xx` (honors `Retry-After`).
- Automatic `Idempotency-Key` for `buy_credits` and `submit_bulk`.
- Typed `VeriflyError(code, message, request_id)` on API error envelopes.

## Install

```bash
pip install verifly-email          # once published
# or, from this repo:
pip install /path/to/sdks/python
```

## Quick start

```python
from verifly_email import VeriflyClient, VeriflyError

client = VeriflyClient("vf_your_api_key")   # base_url defaults to https://verifly.email

try:
    r = client.verify("bill.gates@microsoft.com")
    print(r["result"])           # deliverable | undeliverable | risky | unknown
    print(r["recommendation"])   # safe_to_send | risky | do_not_send
    print(r["credits"])          # {"used": 1, "remaining": 99}
except VeriflyError as e:
    print(e.code, e.message, e.request_id)
```

## Authentication

Every call (except `register`) authenticates with your `vf_` key, sent as
`Authorization: Bearer <api_key>`.

```python
client = VeriflyClient(api_key="vf_...", base_url="https://verifly.email")
```

## Create an account programmatically

```python
res = VeriflyClient.register("you@example.com", "a-strong-password")
api_key = res["api_key"]["key"]   # shown ONCE — store it now
client = VeriflyClient(api_key)
```

## Methods

| Method | Description |
| --- | --- |
| `verify(email)` | Verify a single address. |
| `verify_batch(emails, deduplicate=True, ...)` | Verify up to 100 addresses synchronously. |
| `clean(emails, options=None)` | Clean/filter a list (no verification, no credits). |
| `extract(text, deduplicate=True, lowercase=True)` | Pull email addresses out of text/CSV. |
| `submit_bulk(emails=None, text=None, webhook_url=None, ...)` | Create an async bulk job (up to 1M). |
| `jobs(status=None, limit=None, offset=None)` | List bulk jobs. |
| `job(job_id)` | Get a bulk job's status. |
| `job_results(job_id)` | Get a completed job's per-email results. |
| `account()` | Account profile + credit summary. |
| `credits()` | Current credit balance. |
| `usage(period=None, limit=None)` | API usage summary (day/week/month). |
| `packages()` | List credit packages and prices. |
| `payment_history()` | List payment history. |
| `buy_credits(package_id, method="stripe", currency=None)` | Create a Stripe/crypto checkout. |
| `VeriflyClient.register(email, password)` *(classmethod)* | Self-register, returns account + API key. |

### Examples

```python
# Batch (<=100), synchronous
batch = client.verify_batch(
    ["a@example.com", "b@example.com"],
    exclude_role_accounts=True,
)
for item in batch["results"]:
    print(item["email"], item["result"])

# List hygiene without spending credits
print(client.clean(["A@Example.com ", "a@example.com", "bad"])["..."])
print(client.extract("contact us at sales@acme.io or ceo@acme.io"))

# Async bulk + polling
job = client.submit_bulk(emails=[...], webhook_url="https://you/webhook")
status = client.job(job["job_id"] if "job_id" in job else job["job"]["id"])
results = client.job_results(job_id)

# Account / billing
print(client.credits())
print(client.packages())
checkout = client.buy_credits("pro", method="stripe")
checkout = client.buy_credits("pro", method="crypto", currency="USDT")
```

## Errors

API error envelopes (`{"success": false, "error": {...}}`) and non-2xx
responses raise `VeriflyError`:

```python
try:
    client.verify("nope")
except VeriflyError as e:
    e.code         # e.g. "invalid_email", "insufficient_credits", "rate_limit_exceeded"
    e.message
    e.request_id   # from the x-request-id response header
    e.status       # HTTP status
    e.suggestion   # optional remediation hint
```

## Retries & idempotency

- `429` and `5xx` responses are retried (default 3 times) with exponential
  backoff, honoring the `Retry-After` header. Configure via
  `VeriflyClient(..., max_retries=N, timeout=seconds)`.
- `buy_credits` and `submit_bulk` send an `Idempotency-Key` header. One is
  auto-generated per call; pass your own with `idempotency_key=...` to make a
  specific retry safe end-to-end.

## License

MIT
