Metadata-Version: 2.5
Name: bazi-api-sdk
Version: 2.0.2
Summary: Official Python SDK for the BaZi (Four Pillars of Destiny) API
Project-URL: Homepage, https://baziapi.pro
Project-URL: Documentation, https://baziapi.pro
Author-email: "Md. Nasir Uddin Shoyas" <shoyas@github.com>
License-Expression: MIT
Keywords: ai-agent,api-client,bazi,chinese-astrology,four-pillars,langchain,lunar,sdk
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
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 :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.8
Requires-Dist: pydantic>=1.10.0; python_version < '3.10'
Requires-Dist: pydantic>=2.0.0; python_version >= '3.10'
Provides-Extra: async
Requires-Dist: aiohttp>=3.8.0; extra == 'async'
Provides-Extra: dev
Requires-Dist: black>=23.0.0; extra == 'dev'
Requires-Dist: mypy>=1.0.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.20.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# BaZi API - Official Python SDK (`bazi-api-sdk`)

[![Version](https://img.shields.io/badge/version-1.1.0-blue.svg)](https://github.com/Shoyas/bazi-api-python-sdk/releases)
[![Python CI](https://github.com/Shoyas/bazi-api-python-sdk/actions/workflows/ci.yml/badge.svg)](https://github.com/Shoyas/bazi-api-python-sdk/actions/workflows/ci.yml)
[![PyPI Release](https://github.com/Shoyas/bazi-api-python-sdk/actions/workflows/publish-pypi.yml/badge.svg)](https://github.com/Shoyas/bazi-api-python-sdk/actions/workflows/publish-pypi.yml)
[![Python Versions](https://img.shields.io/badge/python-3.8%20%7C%203.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://pypi.org/project/bazi-api-sdk/)
[![PyPI Package](https://img.shields.io/pypi/v/bazi-api-sdk.svg?color=blue)](https://pypi.org/project/bazi-api-sdk/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Official Python SDK for the [BaZi API Platform](https://baziapi.pro) — the enterprise-grade Chinese Four Pillars of Destiny (八字) astrological calculation engine and real-time webhook infrastructure.

> **What's New in v1.1.0:**
> - **Programmatic Webhook Management**: Register, list, update, and test webhook endpoints directly with your API Key (`client.webhooks.create(...)`, `client.webhooks.list()`, `client.webhooks.test(...)`).
> - **Secure Outbound Webhook Handling**: Constant-time verification (`hmac.compare_digest`) with anti-replay attack timestamp tolerance (`construct_webhook_event`).
> - **Typed Webhook Models**: Dataclasses for `WebhookSubscription`, `WebhookDeliveryLog`, and `WebhookEvent`.

---

## Installation

```bash
pip install --upgrade bazi-api-sdk
```

---

## Quick Start (BaZi Calculation)

Grab your API key from the [BaZi API Dashboard](https://baziapi.pro) and start calculating:

```python
from bazi import BaziClient, BaziError

# Initialize client with your API key
client = BaziClient(api_key="bazi_live_your_api_key_here")

try:
    chart = client.calculate(
        birth_date="1998-08-12",
        birth_time="10:30",
        gender="male",
        timezone="Asia/Shanghai",
        language="en"
    )

    print("Four Pillars:")
    print(f"  Year : {chart.pillars.year}")
    print(f"  Month: {chart.pillars.month}")
    print(f"  Day  : {chart.pillars.day} (Day Master: {chart.heavenly_stems.day_stem})")
    print(f"  Hour : {chart.pillars.hour}")

    print(f"\nDominant Element: {chart.analysis.strongest_element}")
    print(f"Chinese Zodiac  : {chart.zodiac.animal}")

except BaziError as e:
    print(f"Calculation failed: {e}")
```

---

## Programmatic Webhook Management

Manage your outbound webhook subscriptions using your API Key:

```python
from bazi import BaziClient

client = BaziClient(api_key="bazi_live_your_api_key_here")

# 1. Register an endpoint
sub = client.webhooks.create(
    url="https://yourapp.com/api/webhooks/bazi",
    events=["daily.bazi_shift", "solar_term.changed"],
    description="Production astrology push server"
)
print("Registered Webhook ID:", sub.id)
print("Signing Secret:", sub.secret) # Store safely in your .env

# 2. List all endpoints
all_subs = client.webhooks.list()
for item in all_subs:
    print(item.id, item.url, item.events, item.is_active)

# 3. Trigger a live test ping
client.webhooks.test(sub.id)
print("Test ping dispatched to", sub.url)

# 4. View delivery logs
logs = client.webhooks.get_logs(sub.id)
for log in logs:
    print(log.event, log.status, log.status_code, log.created_at)
```

---

## Secure Webhook Receiver (FastAPI / Flask)

Protect against timing attacks and replay attacks with automatic event construction:

### FastAPI Example:

```python
from fastapi import FastAPI, Request, HTTPException, status
from bazi import construct_webhook_event, WebhookVerificationError
import os

app = FastAPI()
WEBHOOK_SECRET = os.environ.get("BAZI_WEBHOOK_SECRET")

@app.post("/api/webhooks/bazi")
async def handle_bazi_webhook(request: Request):
    payload = await request.body()
    signature = request.headers.get("x-bazi-signature")
    timestamp = request.headers.get("x-bazi-timestamp")

    try:
        event = construct_webhook_event(
            payload=payload,
            signature=signature,
            secret=WEBHOOK_SECRET,
            timestamp=timestamp,
            tolerance=300 # 5 minutes replay protection window
        )
    except WebhookVerificationError as err:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail=str(err))

    # Process verified event
    if event.event == "daily.bazi_shift":
        pillar = event.data.get("dayPillar")
        zodiac = event.data.get("zodiac")
        print(f"Daily BaZi Shift: Stem={pillar['gan']} Branch={pillar['zhi']} Zodiac={zodiac}")

    elif event.event == "solar_term.changed":
        term = event.data.get("solarTerm")
        print(f"Solar Term Transition: {term}")

    return {"received": True}
```

---

## AI Agent & LangChain Function Calling

```python
from langchain.tools import tool
from bazi import BaziClient

client = BaziClient(api_key="bazi_live_your_api_key")

@tool
def calculate_bazi(birth_date: str, birth_time: str, gender: str, timezone: str = "Asia/Shanghai") -> dict:
    """Calculates Chinese Four Pillars of Destiny (BaZi) chart."""
    return client.calculate(
        birth_date=birth_date,
        birth_time=birth_time,
        gender=gender,
        timezone=timezone
    ).to_dict()
```

---

## License
MIT License © Md. Nasir Uddin Shoyas
