Metadata-Version: 2.4
Name: hey-pingr
Version: 0.1.1
Summary: Official Python SDK for the Pingr WhatsApp messaging API
Author-email: Pingr <support@heypingr.com>
License: MIT
Project-URL: Homepage, https://heypingr.com
Project-URL: Docs, https://heypingr.com/docs
Project-URL: Repository, https://github.com/heypingr/pingr-python
Keywords: pingr,whatsapp,messaging,otp,api,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
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: Topic :: Communications
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Provides-Extra: async
Requires-Dist: httpx>=0.25; extra == "async"
Provides-Extra: dev
Requires-Dist: httpx>=0.25; extra == "dev"
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-asyncio; extra == "dev"

# pingr

Official Python SDK for the [Pingr](https://heypingr.com) WhatsApp messaging API.

## Installation

```bash
pip install hey-pingr
```

For async support (uses `httpx`):

```bash
pip install hey-pingr[async]
```

## Quick start

```python
import pingr

client = pingr.Pingr("pk_live_your_key_here")

result = client.messages.send(
    to="919876543210",      # digits only, with country code
    message="Your OTP is 482910. Valid for 10 minutes.",
)

print(result["message_id"])           # msg_abc123
print(result["rate_limit_remaining"]) # 499
```

## Async usage

```python
import asyncio
import pingr

async def main():
    async with pingr.AsyncPingr("pk_live_your_key_here") as client:
        result = await client.messages.send(
            to="919876543210",
            message="Your OTP is 482910",
        )
        print(result["message_id"])

asyncio.run(main())
```

## Verifying webhooks

```python
from flask import Flask, request
from pingr import verify_webhook, PingrWebhookError
import os

app = Flask(__name__)

@app.route("/webhook", methods=["POST"])
def webhook():
    try:
        payload = verify_webhook(
            request.get_data(),
            request.headers["x-pingr-signature"],
            os.environ["PINGR_WEBHOOK_SECRET"],
        )
        print(payload["event"], payload["session_id"])
        return "", 200
    except PingrWebhookError as e:
        print("Invalid webhook:", e)
        return "", 400
```

## Error handling

```python
from pingr import Pingr, PingrRateLimitError, PingrAuthError, PingrError

client = Pingr("pk_live_...")

try:
    client.messages.send(to="919...", message="Hello")
except PingrRateLimitError as e:
    print(f"Rate limited. Retry in {e.retry_after}s")
except PingrAuthError:
    print("Invalid API key")
except PingrError as e:
    print(f"Error {e.code}: {e.message}")
```

## Test mode

Use a `pk_test_` key to exercise the API without sending real messages.
The response is identical to live mode — ideal for unit tests and CI.

## API reference

### `Pingr(api_key, *, base_url=..., timeout=15.0)`

### `client.messages.send(*, to, message, session_id=None)`

| Param        | Type | Required | Description                                       |
|--------------|------|----------|---------------------------------------------------|
| `to`         | str  | ✓        | Recipient phone — digits + country code           |
| `message`    | str  | ✓        | Text to send                                      |
| `session_id` | str  |          | Specific session (auto-picks connected if omitted)|

Returns a dict with: `success`, `message_id`, `to`, `session_id`, `rate_limit_remaining`.

### `verify_webhook(raw_body, signature, secret, *, check_timestamp=True)`

Verifies `x-pingr-signature` and returns the parsed payload dict.  
Raises `PingrWebhookError` on failure.

## License

MIT
