Metadata-Version: 2.4
Name: prospectup
Version: 0.1.0
Summary: Official Python SDK for the ProspectUp API (https://api.prospectup.ai/v1).
Project-URL: Documentation, https://api.prospectup.ai/developers
License: MIT
Keywords: api,b2b,leads,prospecting,prospectup,sales,sdk
Requires-Python: >=3.11
Requires-Dist: httpx>=0.24
Description-Content-Type: text/markdown

# ProspectUp Python SDK

The official Python client for the [ProspectUp API](https://api.prospectup.ai/v1).
Typed requests, resource-grouped methods for the whole `/v1` surface, automatic
pagination, retries with backoff, idempotency, and typed errors.

> Generated from the live OpenAPI spec (`scripts/generate.py`) on a hand-written
> runtime core, so the client never drifts from the API.

## Install

```bash
pip install prospectup
```

Requires Python 3.11+. Depends only on [`httpx`](https://www.python-httpx.org/).

## Quick start

```python
from prospectup import ProspectUp

client = ProspectUp(api_key="pk_live_...")  # or set PROSPECTUP_API_KEY

# Reads
balance = client.credits.balance()
prospect = client.prospects.get(8443068)

# Auto-pagination — iterate every page transparently
for p in client.prospects.search(query="coffee", city="Austin"):
    print(p["business_id"], p["display_name"])

# Or just the first page
page = client.leads.search(disposition=["interested"], limit=50)
print(page.data, page.response.get("total"))

# Writes (an Idempotency-Key is attached automatically)
lst = client.lists.create(name="Q3 targets")
client.prospects.save(8443068, list_id=lst["list_id"])
```

## Configuration

```python
ProspectUp(
    api_key="pk_live_...",                    # or PROSPECTUP_API_KEY
    base_url="https://api.prospectup.ai/v1",  # or PROSPECTUP_BASE_URL
    timeout=60.0,                             # per-request, seconds
    max_retries=2,                            # 429/5xx/network, exponential backoff + jitter
)
```

Use it as a context manager to close the underlying connection pool:

```python
with ProspectUp() as client:
    client.dashboard.stats()
```

## Pagination

List methods return a `Page`. It holds the first page (`page.data`, raw
`page.response`) and is **iterable across all pages** — cursor-based and
page-numbered endpoints are both handled automatically.

```python
page = client.prospects.search(query="dentist")
for p in page:            # every prospect, all pages
    ...
everything = page.all()   # collect all (use with care on large sets)
```

## Errors

Every non-2xx raises a typed subclass of `ProspectUpError` carrying `status`,
`code`, `hint`, `retryable`, `details`, and `request_id` (quote it to support).

```python
from prospectup import RateLimitError, PaymentRequiredError, ProspectUpError

try:
    client.prospects.reveal(business_ids=[8443068])
except PaymentRequiredError as e:
    print("Out of credits:", e.hint)
except RateLimitError as e:
    print("Slow down, retry in", e.retry_after_seconds, "s")
except ProspectUpError as e:
    print(e.code, e.request_id)
```

`BadRequestError` (400), `AuthenticationError` (401), `PaymentRequiredError` (402),
`PermissionError` (403), `NotFoundError` (404), `ConflictError` (409),
`RateLimitError` (429), `ServerError` (5xx), `ConnectionError`/`TimeoutError`.

## Idempotency

Writes automatically send a unique `Idempotency-Key`, and a retried write reuses
the same key — so a network hiccup never double-charges. Override it to make your
own call idempotent across process restarts:

```python
client.prospects.reveal(business_ids=[1, 2], idempotency_key="reveal-batch-42")
```

## Verifying webhooks

Deliveries are signed with `X-ProspectUp-Signature: t=<unix>,v1=<hmac-sha256>` over
`<t>.<rawBody>`. Verify with the raw request body before trusting a delivery:

```python
from prospectup import verify_webhook_signature

ok = verify_webhook_signature(
    payload=request.body,                              # the EXACT bytes, not re-serialized
    signature=request.headers.get("X-ProspectUp-Signature"),
    secret=os.environ["PROSPECTUP_WEBHOOK_SECRET"],    # the whsec_... shown once at creation
)
if not ok:
    return Response(status_code=400)
```

## Resources

`account`, `automations`, `batches`, `campaigns`, `conversations`, `credits`,
`dashboard`, `field`, `leads`, `lead_views`, `lists`, `notifications`, `prospects`,
`reference`, `reports`, `saved_filters`, `skips`, `suppressions`, `support`,
`tasks`, `templates`, `webhooks` — 133 methods across the full `/v1` surface. See
the [API reference](https://api.prospectup.ai/developers).

## Development

```bash
python scripts/generate.py           # regenerate resources/types from scripts/openapi.json
PYTHONPATH=src python tests/test_offline.py   # offline runtime tests (mock transport)
```

## License

MIT
