Metadata-Version: 2.5
Name: startupaid
Version: 0.5.0
Summary: Official Python SDK for startupaid — manage apps, send email & push, verify phone numbers with WhatsApp OTP, schedule social posts, and convert currency.
Project-URL: Homepage, https://startupaid.org
Project-URL: Source, https://github.com/StartupAid-Org/startupaid-python
Author: startupaid
License: MIT
Keywords: api,apps,currency,email,otp,push,sdk,social,startupaid,whatsapp
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# startupaid

Official Python SDK for [startupaid](https://startupaid.org) — send transactional
email, send push, verify phone numbers with WhatsApp OTP, schedule social posts,
and convert currency, all with your account API key. Pure standard library, no
dependencies.

## Install

```bash
pip install startupaid
```

Requires Python 3.9+.

## Quick start

```python
from startupaid import Client

sa = Client("sk_your_key")

res = sa.convert("USD", "NGN", 100)
print(f"100 USD = {res['result']} NGN")
```

Create an API key in your startupaid dashboard → **API Keys**.

## Usage

### Email

```python
msg = sa.send_email(
    from_="Acme <hi@acme.com>",
    to="user@example.com",
    subject="Welcome",
    body="<h1>Hi 👋</h1>",
)
status = sa.get_message(msg["id"])
```

Attach files — the helpers base64-encode for you (up to 10 files, 20 MB total):

```python
from startupaid import Client, attach_file, attachment

sa.send_email(
    from_="Acme <hi@acme.com>",
    to="user@example.com",
    subject="Your invoice",
    body="<p>Attached.</p>",
    attachments=[
        attach_file("invoice.pdf"),                       # reads + infers type
        attachment("logo.png", png_bytes, "image/png"),   # from raw bytes
    ],
)
```

### Currency

```python
res = sa.convert("USD", "EUR", 250)
res["result"]        # amount at your rate
sa.rates("USD")
sa.currencies()

# When a custom rate applied, the response also carries the market rate and your
# margin (positive = you keep it):
if "spread" in res:
    res["marketRate"], res["spread"]["percent"], res["spread"]["amount"]
```

### Push

```python
# Register a device token (call again to refresh it).
sa.register_device(
    "app_id",
    token="fcm_or_web_push_token",
    platform="android",  # "web" | "ios" | "android"
    user_ref="u_123",
)

sa.send_push(
    "app_id",
    target={"userRef": "u_123"},
    title="Your order shipped",
    body="Track it in the app.",
)

sa.get_push_message("app_id", "message_id")
```

### Apps

Apps are the account-wide registry every module targets by a unique id (create
once, use for Push, OTP, …). The name is display-only — the id is the key.

```python
app = sa.create_app("Acme")
apps = sa.list_apps()
# app["id"] → "app_9f3k2x8a…" — pass this as app_id to send_otp / the push calls.
```

### OTP (WhatsApp)

```python
# Send a code — we generate, deliver, and track it. app_id picks the app whose
# name is the brand; omit it to use your default app.
ch = sa.send_otp(to="+2348012345678", app_id="app_9f3k2x8a…")

# Later, check the code the user entered.
ok = sa.verify_otp("+2348012345678", "123456")
```

### Social

```python
channels = sa.list_channels()

post = sa.schedule_post(
    channels=[c["id"] for c in channels],
    content="We just shipped 🚀",
    # scheduled_for="2026-08-01T09:00:00Z"  # omit to publish now
)

sa.list_posts()
```

### Loyalty & Rewards

```python
# Run a whole program from your app: create it, then open it.
program = sa.create_loyalty_program(
    name="Moses Rewards",
    tiers=[{"name": "Bronze", "minPoints": 0}, {"name": "Gold", "minPoints": 500, "reward": "Free delivery"}],
    referral_points=50, referee_points=20, points_expire_days=365,
)
sa.set_loyalty_program_status(program["id"], "active")

# Earn moments: by count, by activity key, or by the phone a member added for the till.
sa.award_loyalty_points(program["id"], email="ada@example.com", points=25, event_id="profile:u_123")
sa.award_loyalty_points(program["id"], phone="+447911123456", points=10, reason="In-store")

# Both sides of a referral, once per new member.
sa.record_loyalty_referral(program["id"], referrer_email="moses@example.com", referee_email="new@example.com")

# Spend: a coupon reward hands back its code.
rewards = sa.list_loyalty_rewards(program["id"])
res = sa.redeem_loyalty_reward(program["id"], email="ada@example.com", reward_id=rewards[0]["id"])

# A daily check-in QR by the door.
door = sa.create_loyalty_code(program["id"], code="DOOR", points_value=5, repeat_after_hours=24)
qr = sa.get_loyalty_code_qr(door["id"])
```

### Audiences

```python
sa.list_audiences()
sa.add_contact("audience_id", email="new@example.com", first_name="Ada")
```

## Configuration

```python
Client(
    "sk_your_key",
    base_url="http://localhost:8080",  # self-host / testing
    timeout=30.0,                       # per-request timeout (seconds)
)
```

## Errors

Non-2xx responses raise `startupaidError` with the status code and message:

```python
from startupaid import startupaidError

try:
    sa.convert("USD", "NGN", 1)
except startupaidError as err:
    print(err.status, err.message)
```

Each method requires your account to be subscribed to the matching product
(email, currency, push, otp, social); otherwise the API returns an upgrade prompt.

## License

MIT
