Asynchronous Python SDK for the Wazzup public and tech APIs.
Project description
Wazzup Python SDK
An asynchronous, developer-friendly Python client for the Wazzup public and tech APIs. The package modernises the legacy client by offering typed namespaces, predictable CRUD-style methods, and optional webhook handling utilities.
Table of Contents
- Overview
- Installation
- WazzupClient
- Resource Classes
- WebhooksNamespace
- Data Models
- Context Manager
- Configuration Helpers
- Webhook Listener
- Examples
Overview
An asynchronous, developer-friendly Python client for the Wazzup public and tech APIs. The package modernises the legacy client by offering typed namespaces, predictable CRUD-style methods, and optional webhook handling utilities.
Features
- Async-first API built on
httpx - Typed accessors for key resources (
contacts,users,deals,channels,pipelines,accounts,webhooks) - Automatic fallback to legacy methods to preserve backwards compatibility
- Pydantic models describing public and partner (tech) endpoints
- Built-in pagination helpers (
paginate,paginate_async) - Support for rate limiting and retries through dedicated helpers
- Optional FastAPI/uvicorn webhook listener with authorization checks
- Async context manager helper
wazzup_client_contextfor safe reuse in background tasks
Installation
Install the package from PyPI:
pip install wazzup-pysdk
For development, install in editable mode:
pip install -e .
Extras:
webhooks– installs FastAPI and uvicorn for the embedded listener
pip install wazzup-pysdk[webhooks]
# or for development
pip install -e '.[webhooks]'
Python 3.9 or newer is required.
WazzupClient
The main facade class that provides organized access to the Wazzup API through typed resource namespaces.
Constructor
WazzupClient(
api_key: str,
tech_base_url: str = "https://tech.wazzup24.com",
public_base_url: str = "https://api.wazzup24.com",
*,
timeout: Optional[float] = None,
crm_key: Optional[str] = None,
)
Parameters:
api_key(str): Your Wazzup API keytech_base_url(str): Base URL for technical API endpointspublic_base_url(str): Base URL for public API endpointstimeout(Optional[float]): Request timeout in secondscrm_key(Optional[str]): CRM key for webhook authentication
Properties
contacts: TypedResource[Contact] - Contact managementusers: UsersResource - User management with additional helpersdeals: TypedResource[Deal] - Deal managementpipelines: TypedResource[Pipeline] - Pipeline managementaccounts: AccountsResource - Account operationschannels: ChannelsResource - Channel management with specialized methodswebhooks: WebhooksNamespace - Webhook configuration and event handling
Resource Namespaces
Each namespace is exposed as a TypedResource instance with standard CRUD operations:
| Namespace | Available Methods |
|---|---|
client.contacts |
list, get, create, update, delete |
client.users |
list, get, create, update, delete, list_raw, get_raw, create_many (bulk) |
client.deals |
list, get, create, update, delete |
client.channels |
list, get, create, update, delete, info, reinitialize, generate_link, assign_user, assign_users, remove_user, normalized |
client.pipelines |
list, get, create, update, delete (where available) |
client.accounts |
create, get_settings, update_settings, balance, user_roles |
client.webhooks |
settings, update, ensure, test, start_listener, stop_listener, on decorator |
Methods
async close() -> None
Release underlying client resources and stop webhook listeners.
async __aenter__() -> WazzupClient
Async context manager entry.
async __aexit__(*exc: Any) -> None
Async context manager exit.
__repr__() -> str
String representation showing API key (masked) and available namespaces.
Resource Classes
BaseResource
Generic CRUD wrapper providing a namespace per API resource.
Methods
async list(**params: Any) -> Union[ResourceList[ModelT], Any]
List all items of this resource.
Parameters:
**params: Query parameters to pass to the API
Returns:
ResourceList[ModelT]if model is configured, otherwise raw API response
async get(id: str) -> Union[ModelT, Any]
Fetch a single resource by identifier.
Parameters:
id(str): Resource identifier
Returns:
ModelTif model is configured, otherwise raw API response
async create(**data: Any) -> Union[ModelT, Dict[str, Any]]
Create a new resource instance.
Parameters:
**data: Resource data to create
Returns:
ModelTif model is configured and validation succeeds, otherwise raw response
async update(id: str, **data: Any) -> Union[ModelT, Dict[str, Any]]
Update an existing resource instance.
Parameters:
id(str): Resource identifier**data: Updated resource data
Returns:
ModelTif model is configured and validation succeeds, otherwise raw response
async delete(id: str) -> Dict[str, Any]
Delete a resource by identifier.
Parameters:
id(str): Resource identifier
Returns:
- Dictionary with deletion result
TypedResource
Typed resource that guarantees Pydantic objects for common operations.
Methods
async list(**params: Any) -> ResourceList[ModelT]
List all items with guaranteed typed results.
async get(id: str) -> ModelT
Fetch a single resource with guaranteed typed result.
async create(**data: Any) -> Union[ModelT, Dict[str, Any]]
Create a new resource instance.
async update(id: str, **data: Any) -> Union[ModelT, Dict[str, Any]]
Update an existing resource instance.
ChannelsResource
Additional channel-specific helpers that wrap legacy calls.
Methods
async list(**_params: Any) -> ResourceList[ChannelItem]
List channels and expose normalized payload via .raw.
Returns:
ResourceList[ChannelItem]with normalized raw data
async normalized() -> Dict[str, Any]
Return channels in the historical dict format.
Returns:
- Dictionary with channels and count
async info(transport: str, channel_id: str) -> Dict[str, Any]
Fetch detailed information for a channel.
Parameters:
transport(str): Transport type (whatsapp, telegram, etc.)channel_id(str): Channel identifier
async create(*, transport: str, **data: Any) -> Dict[str, Any]
Create a channel.
Parameters:
transport(str): Transport type**data: Channel creation data
async reinitialize(transport: str, channel_id: str) -> Dict[str, Any]
Reinitialize a channel session.
Parameters:
transport(str): Transport typechannel_id(str): Channel identifier
async delete(*, transport: str, channel_id: str, delete_chats: bool = True) -> Dict[str, Any]
Delete a channel.
Parameters:
transport(str): Transport typechannel_id(str): Channel identifierdelete_chats(bool): Whether to delete associated chats
async generate_link(payload: Mapping[str, Any]) -> Dict[str, Any]
Generate a channel connection link payload.
Parameters:
payload(Mapping[str, Any]): Link generation parameters
async assign_user(user_id: str, channel_id: str, role: str = "seller", allow_get_new_clients: bool = True) -> Any
Assign a single user to a channel with an optional role.
Parameters:
user_id(str): User identifierchannel_id(str): Channel identifierrole(str): User role in channelallow_get_new_clients(bool): Whether user can receive new clients
async assign_users(user_assignments: List[Dict[str, Any]], channel_id: str) -> Any
Assign multiple users to a channel.
Parameters:
user_assignments(List[Dict[str, Any]]): List of user assignment datachannel_id(str): Channel identifier
async remove_user(user_id: str, channel_id: str) -> Any
Remove a user from a channel.
Parameters:
user_id(str): User identifierchannel_id(str): Channel identifier
UsersResource
Typed user resource with raw helpers.
Methods
async list_raw() -> List[Dict[str, Any]]
Return the raw users payload.
async get_raw(user_id: str) -> Dict[str, Any]
Fetch raw user data by identifier.
Parameters:
user_id(str): User identifier
async create_many(users: Sequence[Mapping[str, Any]]) -> Dict[str, Any]
Bulk create or update users.
Parameters:
users(Sequence[Mapping[str, Any]]): List of user data
AccountsResource
Account operations with dedicated helpers.
Methods
async create(*, name: str, lang: str = "ru", currency: str = "RUB", crm_key: Optional[str] = None) -> Dict[str, Any]
Create a new account.
Parameters:
name(str): Account namelang(str): Language codecurrency(str): Currency codecrm_key(Optional[str]): CRM integration key
async get_settings() -> Dict[str, Any]
Fetch account settings.
async settings() -> Dict[str, Any]
Backward compatible alias for get_settings.
async update_settings(**params: Any) -> Dict[str, Any]
Update account settings.
Parameters:
**params: Settings to update
async balance() -> Dict[str, Any]
Get account balance.
async get_balance() -> Dict[str, Any]
Backward compatible alias for balance.
async user_roles(user_id: str) -> List[Dict[str, Any]]
Return user roles across channels.
Parameters:
user_id(str): User identifier
WebhooksNamespace
Manage webhook API settings and expose a local webhook listener.
Constructor
WebhooksNamespace(expected_bearer: Optional[str] = None)
Properties
events: WebhookEventRouter - Event router for handling webhooksurl: str - Current webhook listener URL
Methods
async settings() -> WebhooksSettings
Get current webhook settings.
async update(settings: Union[WebhooksSettings, Mapping[str, Any]]) -> WebhooksSettings
Update webhook settings.
Parameters:
settings: Webhook settings as model or dictionary
async ensure(*, uri: str, auth_token: Optional[str] = None, subscriptions: Union[WebhookSubscriptions, Mapping[str, Any], None] = None) -> WebhooksSettings
Ensure webhook settings are configured.
Parameters:
uri(str): Webhook endpoint URIauth_token(Optional[str]): Authentication tokensubscriptions(Optional): Event subscriptions
async test(uri: str) -> Dict[str, Any]
Test webhook endpoint.
Parameters:
uri(str): Webhook URI to test
async start_listener(*, host: str = "0.0.0.0", port: int = 8080, path: str = "/webhooks", log_level: str = "warning", require_bearer: Optional[str] = None) -> str
Start local webhook listener.
Parameters:
host(str): Listen hostport(int): Listen portpath(str): Webhook pathlog_level(str): Logging levelrequire_bearer(Optional[str]): Required bearer token
Returns:
- Listener URL
async stop_listener() -> None
Stop webhook listener.
on(event: Union[str, Type[BaseModel]]) -> Callable[[Handler], Handler]
Decorator to register webhook event handlers.
Parameters:
event: Event name or Pydantic model class
Returns:
- Decorator function
expect_bearer(token: Optional[str]) -> None
Set expected bearer token for webhook authentication.
Parameters:
token(Optional[str]): Bearer token
async close() -> None
Close webhook namespace and stop listeners.
Data Models
Core Models
User
class User(BaseModel):
id: str # Max 64 characters
name: str # Max 150 characters
phone: Optional[str] = None # 8-15 digits
Contact
class Contact(BaseModel):
id: str # Max 100 characters
name: str # Max 200 characters
data: List[ContactData]
uri: Optional[str] = None # Max 200 characters
ContactData
class ContactData(BaseModel):
chatType: str # whatsapp, whatsgroup, viber, instagram, telegram, telegroup, vk, avito, max, maxgroup
chatId: Optional[str] = None
username: Optional[str] = None
phone: Optional[str] = None # 8-15 digits, only for telegram/max
Deal
class Deal(BaseModel):
id: str # Max 100 characters
responsibleUserId: str # Max 100 characters
name: str # Max 200 characters
contacts: List[str] # 1-10 contact IDs
uri: str # Max 200 characters
closed: Optional[bool] = None
Pipeline
class Pipeline(BaseModel):
id: str # Max 100 characters
name: str # Max 200 characters
stages: List[PipelineStage]
uri: str # Max 200 characters
PipelineStage
class PipelineStage(BaseModel):
id: str # Max 100 characters
name: str # Max 100 characters
order: int
color: Optional[str] = None
uri: str # Max 200 characters
ChannelItem
class ChannelItem(BaseModel):
id: str
name: str
transport: str
status: str
# Additional fields vary by transport
Webhook Models
WebhooksSettings
class WebhooksSettings(BaseModel):
webhooksUri: Optional[str] = None
webhooksAuthToken: Optional[str] = None
subscriptions: Optional[WebhookSubscriptions] = None
WebhookSubscriptions
class WebhookSubscriptions(BaseModel):
messages: Optional[bool] = None
statuses: Optional[bool] = None
createEntities: Optional[bool] = None
channelsUpdates: Optional[bool] = None
templateStatus: Optional[bool] = None
MessagesWebhook
class MessagesWebhook(BaseModel):
messages: List[WebhookMessageItem]
StatusesWebhook
class StatusesWebhook(BaseModel):
statuses: List[StatusItem]
CreateEntitiesWebhook
class CreateEntitiesWebhook(BaseModel):
createContact: Optional[CreateContactPayload] = None
createDeal: Optional[CreateDealPayload] = None
Message Models
MessageSendRequest
class MessageSendRequest(BaseModel):
channelId: str
chatType: str # whatsapp, whatsgroup, viber, instagram, telegram, telegroup, vk, avito, max, maxgroup
chatId: Optional[str] = None
text: Optional[str] = None
contentUri: Optional[AnyUrl] = None
refMessageId: Optional[str] = None
crmUserId: Optional[str] = None
crmMessageId: Optional[str] = None
username: Optional[str] = None
phone: Optional[str] = None # 8-15 digits
clearUnanswered: Optional[bool] = None
templateId: Optional[str] = None
templateValues: Optional[List[str]] = None
buttonsObject: Optional[ButtonsObject] = None
MessageSendResponse
class MessageSendResponse(BaseModel):
messageId: str
chatId: Optional[str] = None
# Additional response fields
Context Manager
wazzup_client_context
Async context manager that yields a WazzupClient and closes it automatically.
async def wazzup_client_context(
api_key: str,
*,
tech_base_url: str = "https://tech.wazzup24.com",
public_base_url: str = "https://api.wazzup24.com",
timeout: Optional[float] = None,
crm_key: Optional[str] = None,
) -> AsyncIterator[WazzupClient]:
Parameters:
api_key(str): Your Wazzup API keytech_base_url(str): Base URL for technical API endpointspublic_base_url(str): Base URL for public API endpointstimeout(Optional[float]): Request timeout in secondscrm_key(Optional[str]): CRM key for webhook authentication
Examples
Basic Usage
import asyncio
from wazzup_client.client import WazzupClient
async def main():
client = WazzupClient(api_key="your_api_key")
# List contacts
contacts = await client.contacts.list()
for contact in contacts:
print(f"Contact: {contact.name}")
# Create a new contact
new_contact = await client.contacts.create(
name="John Doe",
data=[{
"chatType": "whatsapp",
"chatId": "1234567890"
}]
)
await client.close()
asyncio.run(main())
Using Context Manager
import asyncio
from wazzup_client.client import wazzup_client_context
async def main():
async with wazzup_client_context(api_key="your_api_key") as client:
# List users
users = await client.users.list()
print(f"Found {len(users)} users")
# Get account balance
balance = await client.accounts.balance()
print(f"Account balance: {balance}")
asyncio.run(main())
Webhook Handling
import asyncio
from wazzup_client.client import WazzupClient
from wazzup_client.public.schemas import MessagesWebhook
async def main():
client = WazzupClient(api_key="your_api_key", crm_key="your_crm_key")
# Register webhook handlers
@client.webhooks.on("messages")
async def handle_messages(payload: dict):
print(f"Received message: {payload}")
@client.webhooks.on(MessagesWebhook)
async def handle_typed_messages(webhook: MessagesWebhook):
for message in webhook.messages:
print(f"Message from {message.senderName}: {message.text}")
# Start webhook listener
url = await client.webhooks.start_listener(port=8080)
print(f"Webhook listener started at {url}")
# Configure webhooks
await client.webhooks.ensure(
uri=url,
auth_token="your_crm_key",
subscriptions={
"messages": True,
"statuses": True
}
)
# Keep running
try:
await asyncio.sleep(3600) # Run for 1 hour
finally:
await client.close()
asyncio.run(main())
Channel Management
import asyncio
from wazzup_client.client import WazzupClient
async def main():
client = WazzupClient(api_key="your_api_key")
# List channels
channels = await client.channels.list()
print(f"Found {len(channels)} channels")
# Get channel info
channel_info = await client.channels.info("whatsapp", "channel_id")
print(f"Channel info: {channel_info}")
# Assign user to channel
await client.channels.assign_user(
user_id="user_id",
channel_id="channel_id",
role="seller"
)
await client.close()
asyncio.run(main())
Bulk Operations
import asyncio
from wazzup_client.client import WazzupClient
async def main():
client = WazzupClient(api_key="your_api_key")
# Bulk create users
users_data = [
{"id": "user1", "name": "User One", "phone": "1234567890"},
{"id": "user2", "name": "User Two", "phone": "0987654321"}
]
result = await client.users.create_many(users_data)
print(f"Created users: {result}")
# Bulk assign users to channel
assignments = [
{"userId": "user1", "role": "seller"},
{"userId": "user2", "role": "manager"}
]
await client.channels.assign_users(assignments, "channel_id")
await client.close()
asyncio.run(main())
Webhook Listener
The SDK includes a FastAPI-based webhook listener that can be started from client.webhooks. This is optional and mostly intended for local development or lightweight deployments.
Typed payload parsing without the router
If you already have an HTTP endpoint, use parse_webhook_payload for lightweight, typed dispatch:
from typing import Any, Mapping
from wazzup_client.public.schemas import ChannelsUpdatesWebhook, MessagesWebhook
from wazzup_client.webhook_events import parse_webhook_payload
async def handle_wazzup_webhook(payload: Mapping[str, Any]) -> None:
parsed = parse_webhook_payload(payload)
if parsed.name == "messages":
event = parsed.require_model(MessagesWebhook)
for message in event.messages:
print(f"[{message.channelId}] {message.text}")
elif parsed.name == "channelsUpdates":
updates = parsed.require_model(ChannelsUpdatesWebhook)
print(f"{len(updates.channelsUpdates)} channels updated")
else:
# Unknown webhook payload – fall back to raw dict
print(parsed.payload)
Combine this with your own bearer validation logic or reuse client.webhooks.expect_bearer(token) to align with CRM secrets.
Starting the listener
import asyncio
from wazzup_client.client import WazzupClient
from wazzup_client.public.schemas import MessagesWebhook
async def bootstrap_webhooks():
async with WazzupClient(api_key="client-key", crm_key="crm-key") as client:
listener_url = await client.webhooks.start_listener(
host="0.0.0.0",
port=8080,
path="/webhooks",
)
# Update Wazzup with the listener settings
await client.webhooks.ensure(
uri=listener_url,
auth_token="crm-key",
subscriptions={"messagesAndStatuses": True},
)
@client.webhooks.on(MessagesWebhook)
async def handle_messages(event: MessagesWebhook) -> None:
for message in event.messages:
print(f"{message.channelId}: {message.text}")
# Keep the listener running until cancelled
await asyncio.Event().wait()
if __name__ == "__main__":
asyncio.run(bootstrap_webhooks())
Key points:
- Passing
crm_keytoWazzupClientautomatically enforces the expectedAuthorization: Bearerheader for inbound webhooks start_listener(require_bearer="...")can override the stored token at runtime- Use
client.webhooks.ensure()to configure the webhook URI and subscriptions on the Wazzup API - For manual testing, the router exposes
dispatch()so you can trigger handlers with sample payloads without starting FastAPI
License
MIT License. See LICENSE for details.
Project details
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 wazzup_pysdk-0.1.5.tar.gz.
File metadata
- Download URL: wazzup_pysdk-0.1.5.tar.gz
- Upload date:
- Size: 45.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ddc09af53f05983888490114415e27558643d5d7429b8dba469a4c84b435ba0
|
|
| MD5 |
d119d2130f8a8fc2df8be25cf60db205
|
|
| BLAKE2b-256 |
d1cdfcff7ac90a53354d0ce2fb450faf68c3d56c3b33a341e13d8d6d6c16ca5c
|
File details
Details for the file wazzup_pysdk-0.1.5-py3-none-any.whl.
File metadata
- Download URL: wazzup_pysdk-0.1.5-py3-none-any.whl
- Upload date:
- Size: 46.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
009f9e1a7559dd7f65c51cc1e7c35301183f656addb7e1dd4620d7046fdabc19
|
|
| MD5 |
ce47605c56316d873e904b619efdff4f
|
|
| BLAKE2b-256 |
3a6a32b0e32af57bfcfe69158bf93b75fd95cc09a4aa5a15ee9a9ca6e52619c6
|