Metadata-Version: 2.4
Name: thunderphone
Version: 0.2.0
Summary: Official typed ThunderPhone API client
Author: ThunderPhone
License-Expression: MIT
Project-URL: Documentation, https://thunderphone.com/docs/api-reference/sdks
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<0.29,>=0.27
Requires-Dist: attrs>=23.2
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: typing-extensions>=4.10
Dynamic: license-file

# ThunderPhone Python SDK

Python 3.10+. Install `pip install thunderphone`. Set `THUNDERPHONE_API_KEY` in your
environment, or pass `api_key=` to `ThunderPhone`. Optional `base_url` defaults to
`https://api.thunderphone.com` (do not append `/v1`).

```python
import os
from thunderphone import ThunderPhone, AgentRequest, PlaceCallRequest

with ThunderPhone() as api:
    agent = api.agents.create(AgentRequest(
        name="Reception",
        prompt="Help callers with scheduling and business information.",
        voice=os.environ["THUNDERPHONE_VOICE"],
    ))
    call = api.calls.place(PlaceCallRequest(
        agent_id=agent.id,
        from_number=os.environ["FROM_NUMBER"],
        to_number=os.environ["TO_NUMBER"],
        idempotency_key="appointment-123",
    ))
    done = api.calls.wait_for_completion(
        call.call_id, timeout=300, poll_interval=1,
    )
    if done.status == "failed":
        raise RuntimeError(done.end_reason)
    print(api.calls.transcript(call.call_id).transcripts)
```

Choose a voice from `GET /v1/voices`. Outbound calls require an outbound-capable
carrier number, sufficient balance, and the organization's outbound confirmation.
Polling returns both completed and failed calls. A polling deadline raises
`TimeoutError`; HTTP timeouts and transport errors propagate. Writes are never
retried automatically. Reuse an idempotency key only for the same request.

Every operation has generated synchronous and asynchronous functions and typed
request/response models under `thunderphone.generated`. For example:

```python
from thunderphone.generated.api.calls import calls_list

with ThunderPhone() as api:
    page = calls_list.sync(client=api.client, limit=20, offset=0)
```

Generated functions offer `sync`, `sync_detailed`, `asyncio`, and `asyncio_detailed`
where the operation has a response body. Detailed variants retain status and headers;
undocumented errors return `parsed=None` unless `raise_on_unexpected_status` is enabled
on the generated client. Helpers raise `ThunderPhoneError` with `status` and `body`.
The client sends `X-ThunderPhone-Client: sdk-python/0.2.0`. Use a context manager or
`close()` for the facade; close generated async clients with their async context manager.

## Verify webhook and tool-call signatures

Every request ThunderPhone sends to your server carries
`X-ThunderPhone-Signature-V2`, a timestamped HMAC over the method, path, query and
raw body. `verify_signature` checks it and rejects requests older than five minutes:

```python
from thunderphone import verify_signature

ok = verify_signature(
    request.headers.get("X-ThunderPhone-Signature-V2"),
    secret=os.environ["THUNDERPHONE_WEBHOOK_SECRET"],  # or a list while rotating
    method=request.method,
    path="/thunderphone-webhook?source=prod",  # path and query exactly as received
    body=raw_body,  # the raw bytes, before any JSON parsing
)
```

`tolerance=` changes the 300-second window. `compute_signature` builds a signature
for your own tests. The module uses only the standard library. See
[Verify webhook signatures](https://thunderphone.com/docs/guides/verify-webhook-signatures).

[API reference](https://thunderphone.com/docs/api-reference/sdks) ·
[OpenAPI](https://thunderphone.com/openapi.json)

Development: `pip install -e .`, `python -m unittest discover -s tests -v`,
`python -m build`. Regenerate from the repository root using
`scripts/generate-sdks.sh`; never edit `thunderphone/generated/` by hand.
