Metadata-Version: 2.4
Name: vact-server
Version: 1.0.0
Summary: Server-only VACT client: mint access tokens and verify webhooks. No dependencies.
Project-URL: Homepage, https://vact.online/docs.html
Project-URL: Documentation, https://vact.online/docs.html
License: Copyright (c) 2026 VACT. All rights reserved.
        
        This package is currently provided for private evaluation. Redistribution and
        publication require written permission from VACT.
License-File: LICENSE
Keywords: calling,vact,video-call,voip,webrtc
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Communications :: Telephony
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# `vact-server`

Server-only VACT client for Python. **No dependencies** — standard library only.

```bash
pip install vact-server
```

Your backend is the only place the App Secret ever lives. It authenticates
your own user, then asks VACT for a short-lived token scoped to them.

```python
from vact_server import VactServer

vact = VactServer(
    app_id=os.environ["VACT_APP_ID"],
    app_secret=os.environ["VACT_APP_SECRET"],
)

# After YOUR login has decided who this is:
token = vact.create_access_token(
    user_id=current_user.id,
    allowed_callee_ids=["user_42"],   # optional: restrict who they may call
)
return {"accessToken": token["accessToken"]}
```

## Verifying webhooks

Pass the **raw request bytes**. Re-serializing parsed JSON changes the bytes
and the signature will not match.

```python
from vact_server import verify_vact_webhook, VactServerError

@app.post("/webhooks/vact")
async def webhook(request):
    try:
        event = verify_vact_webhook(
            await request.body(),          # raw bytes, not the parsed dict
            dict(request.headers),
            os.environ["VACT_WEBHOOK_SECRET"],
        )
    except VactServerError:
        return Response(status_code=400)   # never process an unverified body

    # Deduplicate on event["eventId"] — delivery is retried.
    if event["type"] == "incoming_call":
        send_push(event["data"]["toUserId"], event["data"])
    return Response(status_code=200)
```

Signature verification is timing-safe and rejects deliveries whose timestamp
is more than five minutes old, which stops replay.

## Deleting a user's data

```python
result = vact.delete_user_data(user_id)   # pages internally until complete
```

Full documentation: <https://vact.online/docs.html>
