Modern Python Doppel client — sync and async — powered by HTTPX
Project description
doppel-api
Modern, type-safe Python client for the Doppel API — built on HTTPX for first-class sync and async support.
API Reference: https://doppel.readme.io/reference/
Features
- Sync and async — identical API surface via
Doppel(sync) andAsyncDoppel(async) - Type-safe — Pydantic v2 models for every request and response payload
- Semantic exceptions — typed error hierarchy for clean error handling
- Webhook parsing — lightweight
parse_webhook()utility for inbound events - Modern Python — 3.11+, built-in generics, union types, no legacy
typingimports - Minimal dependencies — just
httpxandpydantic
Installation
pip install doppel-api
# or
uv add doppel-api
Quick Start
from doppel import Doppel
client = Doppel(api_key="your-gw-key", user_api_key="your-user-key")
# Create an alert
alert = client.alerts.create(entity="https://suspicious-site.com")
# Get an alert by ID
alert = client.alerts.get(id="TST-1234")
# List alerts with filters
alerts = client.alerts.list(queue_state="monitoring", page_size=50)
# List brands
brands = client.brands.list()
# List and create protected assets
assets = client.protected_assets.list(platform_name="linkedin")
new_asset = client.protected_assets.create(
brand_ids=["brand-id"],
asset_value="https://linkedin.com/company/acme",
)
client.close()
Context Manager
from doppel import Doppel
with Doppel(api_key="your-gw-key", user_api_key="your-user-key") as client:
alert = client.alerts.get(id="TST-1234")
Asynchronous
import asyncio
from doppel import AsyncDoppel
async def main():
async with AsyncDoppel(api_key="your-gw-key", user_api_key="your-user-key") as client:
alert = await client.alerts.get(id="TST-1234")
brands = await client.brands.list()
asyncio.run(main())
Multi-Organization Support
client = Doppel(
api_key="your-gw-key",
user_api_key="your-user-key",
organization_code="my-org",
)
Webhook Parsing
Parse inbound webhook payloads from Doppel — no framework dependency required:
from doppel.webhooks import parse_webhook
event = parse_webhook(request_body)
# Returns AlertUpdatedEvent | ReportSurfacedEvent | UrlSurfacedEvent | SMSResponseEvent | IOCUpdatedEvent
Error Handling
from doppel import Doppel, NotFoundError, RateLimitError
client = Doppel(api_key="gw-key", user_api_key="user-key")
try:
alert = client.alerts.get(id="NONEXISTENT")
except NotFoundError:
print("Alert not found")
except RateLimitError as e:
print(f"Rate limited — retry after {e.retry_after}s")
API Coverage
| Resource | Methods |
|---|---|
| Alerts | create, get, update, list, submit_referrer_logs |
| Brands | list |
| Protected Assets | list, create |
| Reports (deprecated) | submit, get, update, list |
| Webhooks | parse_webhook() utility |
Development
# Install dependencies
task setup # uv sync --all-groups
# Run quality checks
task check # lint + format check + typecheck + tests
# Run tests with coverage
task test:cov # uv run pytest --cov=doppel tests/unit
Architecture
doppel/
├── __init__.py # Public API: Doppel, AsyncDoppel, exceptions
├── client.py # Doppel + AsyncDoppel with @cached_property resources
├── _base_client.py # Shared HTTP logic, dual API key auth
├── _resource.py # SyncAPIResource / AsyncAPIResource base classes
├── exceptions.py # DoppelError hierarchy
├── models/
│ ├── __init__.py # Re-exports all models
│ ├── alerts.py # AlertResponse, enums, pagination
│ ├── reports.py # ReportResponse (deprecated)
│ ├── brands.py # BrandResponse
│ ├── protected_assets.py # ProtectedAssetResponse, Platform enum
│ └── webhooks.py # Webhook event payloads
├── alerts.py # Alerts + AsyncAlerts resource
├── reports.py # Reports + AsyncReports resource (deprecated)
├── brands.py # Brands + AsyncBrands resource
├── protected_assets.py # ProtectedAssets + AsyncProtectedAssets resource
├── webhooks.py # parse_webhook() utility
└── py.typed # PEP 561 marker
Contributing
Contributions are welcome! Please open an issue first to discuss proposed changes. See the Development section for setup instructions.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file doppel_api-0.1.0.tar.gz.
File metadata
- Download URL: doppel_api-0.1.0.tar.gz
- Upload date:
- Size: 63.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3fffb1a6e545971a5046e0d9837109e33940482ad40894471204a14e00583ac1
|
|
| MD5 |
46be297573e339ff27a2927328944dab
|
|
| BLAKE2b-256 |
58d11a454899a06f225d9d335d6fb378810b684265e0b30420ae2f847426eeb4
|
File details
Details for the file doppel_api-0.1.0-py3-none-any.whl.
File metadata
- Download URL: doppel_api-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.9 {"installer":{"name":"uv","version":"0.10.9","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4f202e9a2344947cacfd2b912d9b643c20826c0eb5b20933d589a358f6fc349e
|
|
| MD5 |
1e1f1fc290b0e3630bb48b096b167b62
|
|
| BLAKE2b-256 |
4ed102e129e7258d73419f5146216480430c29adbf187261aa4ab9045d6dc187
|