Metadata-Version: 2.4
Name: devotel-orbit-sdk
Version: 0.1.0
Summary: Official Python SDK for Orbit by Devotel — CPaaS APIs for SMS, WhatsApp, voice, email, RCS, agents, and more.
License: MIT
License-File: LICENSE
Keywords: cpaas,sms,whatsapp,voice,email,rcs,orbit,devotel
Author: Devotel
Author-email: support@devotel.io
Requires-Python: >=3.9,<4.0
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
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: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Communications
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: typing-extensions (>=4.7,<5.0)
Requires-Dist: urllib3 (>=2.0,<3.0)
Project-URL: Documentation, https://docs.orbit.devotel.io
Project-URL: Homepage, https://docs.orbit.devotel.io
Project-URL: Repository, https://github.com/Devotel/orbit-python
Description-Content-Type: text/markdown

# devotel-orbit-sdk

Official Python SDK for **Orbit by Devotel** — CPaaS APIs for SMS, WhatsApp,
voice, email, RCS, agents, conversations, campaigns, billing, and more.

## Installation

```bash
pip install devotel-orbit-sdk
# or
poetry add devotel-orbit-sdk
```

Requires Python **3.9+**.

## Quick start

```python
from orbit_sdk import OrbitClient

client = OrbitClient.from_api_key("dv_live_sk_...")

# Send SMS
msg = client.messages.send_sms(to="+14155552671", body="Hello from Orbit!")
print(msg["data"]["id"])

# Send WhatsApp
client.messages.send_whatsapp(to="+14155552671", body="Hello on WhatsApp!")

# Send email
client.messages.send_email(
    to="user@example.com",
    subject="Welcome",
    body="Thanks for signing up.",
)
```

You can also load the API key from an environment variable:

```python
# Reads ORBIT_API_KEY by default
client = OrbitClient.from_env()
```

## Resources

Each resource is a thin, typed wrapper over the platform's real route paths.

### Voice

```python
# Initiate an outbound call. Termination is handled server-side by the
# Devotel softswitch — the SDK never selects a carrier.
call = client.voice.create(to="+14155552671", from_="+14155550000", record=True)
client.voice.get(call["data"]["id"])
client.voice.hangup(call["data"]["id"])
```

### Verify (OTP)

```python
sent = client.verify.send(to="+14155552671", channel="sms")  # sms | whatsapp | email
client.verify.check(verification_id=sent["data"]["id"], code="123456")
client.verify.get_detail(sent["data"]["id"])
```

### Numbers

```python
# Search inventory, then purchase.
available = client.numbers.search(country="US", type="local", capabilities=["sms", "voice"])
client.numbers.purchase(number="+14155552671")
client.numbers.list()
client.numbers.get("num_123")
```

### Lookup (HLR number intelligence)

```python
client.lookup.number("+14155552671")             # validity, carrier, line type
client.lookup.bulk(["+14155552671", "+442071838750"])  # up to 100 per request
```

## Authentication

The SDK authenticates with the `X-API-Key` header. Generate a key from the
Orbit dashboard's **Developers → API keys** page. Keys are prefixed:

- `dv_live_sk_...` — production-scoped server key.
- `dv_test_sk_...` — sandbox-scoped key (free, sends to test numbers only).

Treat keys as secrets — never commit them to source control.

## Configuration

```python
client = OrbitClient(
    api_key="dv_live_sk_...",
    base_url="https://api.orbit.devotel.io/api/v1",  # defaults to prod
    timeout_s=30.0,                                  # per-request timeout
    max_retries=3,                                   # 429/5xx retry budget
    initial_backoff_s=1.0,                           # 1s → 2s → 4s
)
```

## Error handling

All Orbit-originated errors inherit from `OrbitError`:

```python
from orbit_sdk import (
    OrbitError,
    OrbitAuthenticationError,    # 401/403
    OrbitClientError,            # other 4xx
    OrbitRateLimitError,         # 429 after retries exhausted
    OrbitServerError,            # 5xx after retries exhausted
)

try:
    client.messages.send_sms(to="+14155552671", body="...")
except OrbitRateLimitError as exc:
    print(f"throttled — retry in {exc.retry_after}s")
except OrbitAuthenticationError:
    print("bad API key — rotate it")
except OrbitError as exc:
    print(f"orbit error: {exc.code} ({exc.status}) — {exc.message}")
```

Network failures are retried up to `max_retries`; persistent network errors
surface as `OrbitServerError` with `code="network_error"`.

## Idempotency

Every non-GET request automatically carries an `Idempotency-Key` header (a
fresh UUIDv4 per call), so a 429/5xx retry never produces a duplicate
charge on billable submit paths. Provide your own key when retrying from
your own queue:

```python
client.messages.send_sms(
    to="+14155552671",
    body="...",
    idempotency_key="job-7a3b9d-attempt-1",
)
```

## Webhook signature verification

```python
from orbit_sdk import verify_webhook, OrbitWebhookSignatureError

@app.post("/webhooks/orbit")
def handler(request):
    try:
        event = verify_webhook(
            payload=request.body,                            # bytes
            signature=request.headers["X-Devotel-Signature"],
            secret=os.environ["ORBIT_WEBHOOK_SECRET"],
        )
    except OrbitWebhookSignatureError:
        # Forgery attempt — drop, do not 200.
        return Response(status=400)

    # event is a dict — act on event["type"], event["data"], ...
    return Response(status=200)
```

Signatures use the format `t=<unix_ts>,v1=<hex_hmac>` (same as Stripe) and
include a 5-minute replay window enforced by default.

## How it's built

This SDK is fully hand-written. The `orbit_sdk` package is the entire
public surface — there is no generated code and no separate internal
package to install. HTTP requests go through the Python standard library
(`urllib.request`), keeping the dependency footprint small. Import
everything you need from `orbit_sdk`.

## Support

- Docs: <https://docs.orbit.devotel.io>
- Issues: <https://github.com/dddFEDDDDDd/devotel-cpaas/issues>
- Email: <support@devotel.io>

## License

MIT © 2026 Devotel.

