Metadata-Version: 2.5
Name: waapi
Version: 0.1.1
Summary: Official Python SDK for the WaAPI REST API
Project-URL: Homepage, https://waapi.app
Project-URL: Documentation, https://waapi.app/docs
Project-URL: Source, https://github.com/WaAPIapp/waapi-python-sdk
Project-URL: Issues, https://github.com/WaAPIapp/waapi-python-sdk/issues
Author-email: WaAPI <info@waapi.app>
License-Expression: MIT
License-File: LICENSE
Keywords: api,automation,chatbot,messaging,sdk,waapi
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: httpx<1.0,>=0.24
Provides-Extra: dev
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=7; extra == 'dev'
Requires-Dist: respx>=0.20; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# WaAPI Python SDK

Official Python client for the [WaAPI](https://waapi.app) REST API — send and
receive WhatsApp messages, manage chats, groups and channels from Python.

[![PyPI](https://img.shields.io/pypi/v/waapi?style=for-the-badge)](https://pypi.org/project/waapi/)
[![Python](https://img.shields.io/pypi/pyversions/waapi?style=for-the-badge)](https://pypi.org/project/waapi/)
[![License](https://img.shields.io/badge/license-MIT-blue?style=for-the-badge)](LICENSE)

```bash
pip install waapi
```

## Quick start

```python
from waapi import WaAPI

client = WaAPI(token="YOUR_API_TOKEN", instance_id=123)

client.send_message(
    chat_id="4915112345678@c.us",
    message="Deployment finished.",
)
```

Get a token at [waapi.app/user/api-tokens](https://waapi.app/user/api-tokens)
and create an instance connected to your number.

### The chat ID is the one thing to get right

Its suffix decides where the message lands, and a wrong suffix is accepted and
delivers nothing:

| Target | Format |
|---|---|
| One person | `4915112345678@c.us` |
| Group | `123456789-123456789@g.us` |
| Channel | `123456789@newsletter` |

## Async

Same method names, awaited:

```python
from waapi import AsyncWaAPI

async with AsyncWaAPI(token="YOUR_API_TOKEN", instance_id=123) as client:
    await client.send_message(chat_id="4915112345678@c.us", message="Hi")
```

## Errors

A successful HTTP exchange is not proof the message was sent. The API answers
`200` with `{"status": "error"}` when, for example, the instance is not
connected — so the SDK raises on that too, rather than handing back a body that
looks like success.

```python
from waapi import WaAPI, FailedActionError, AuthenticationError, RateLimitError

try:
    client.send_message(chat_id="4915112345678@c.us", message="Hi")
except AuthenticationError:
    ...                      # token wrong, expired, or missing scopes
except RateLimitError as e:
    time.sleep(e.retry_after or 5)
except FailedActionError as e:
    ...                      # accepted but not carried out — e.response has the detail
```

| Exception | Raised on |
|---|---|
| `AuthenticationError` | HTTP 401, 403 |
| `NotFoundError` | HTTP 404 |
| `ValidationError` | HTTP 422 — `.errors` holds the field errors |
| `RateLimitError` | HTTP 429 — `.retry_after` in seconds when the API sends it |
| `FailedActionError` | HTTP 400, **and HTTP 200 with `status: error`** |
| `ServerError` | HTTP 5xx |

All inherit from `WaAPIError`.

## Coverage

All **122 client actions** are wrapped, typed, and available on both clients:

```python
client.create_group(group_name="Ops", group_participants=["4915112345678@c.us"])
client.send_media(chat_id="4915112345678@c.us", media_url="https://example.com/report.pdf")
client.get_contacts()
```

They are generated from the same OpenAPI specification the n8n node and the MCP
tools come from, so they track the API instead of drifting behind it — see
[CONTRIBUTING.md](CONTRIBUTING.md).

An action added to the API since the last release is still reachable by name:

```python
client.action("some-new-action", {"chatId": "4915112345678@c.us"})
```

## Configuration

```python
WaAPI(
    token="...",              # required
    instance_id=123,          # optional; per-call instance_id overrides it
    base_url="https://waapi.app/api/v1",
    timeout=30.0,
)
```

Passing `instance_id` to the client keeps single-instance code short. Any call
can still override it, and a call with neither raises before a request is sent.

## Development

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest
```

The suite runs entirely against `httpx.MockTransport` — no network, no token,
no connected account.

## License

MIT. Not affiliated with, endorsed or sponsored by WhatsApp LLC or Meta.
WhatsApp is a trademark of WhatsApp LLC.
