Skip to main content

Python SDK

The official Devotel Python SDK provides an idiomatic Python client for the Devotel API with full type hints, async support, and automatic retries.

Installation

pip install devotel
Or with Poetry:
poetry add devotel

Quick Start

from devotel import Devotel

orbit = Devotel(api_key="dv_live_sk_your_key_here")

# Send an SMS
message = orbit.messages.send(
    channel="sms",
    to="+14155552671",
    body="Hello from Orbit!"
)

print(message["data"]["message_id"])  # msg_abc123

Messaging

# Send WhatsApp template
wa_message = orbit.messages.send(
    channel="whatsapp",
    to="+14155552671",
    type="template",
    template={
        "name": "order_confirmation",
        "language": "en",
        "components": [
            {"type": "body", "parameters": [{"type": "text", "text": "ORD-12345"}]}
        ]
    }
)

# Send Email
email = orbit.messages.send(
    channel="email",
    to="user@example.com",
    from_address="hello@yourdomain.com",
    subject="Welcome!",
    html="<h1>Welcome to Acme</h1>"
)

Voice

# Make an outbound call
call = orbit.voice.create_call(
    to="+14155552671",
    from_number="+18005551234",
    webhook_url="https://yourapp.com/webhooks/voice"
)

# Connect to an AI agent
agent_call = orbit.voice.create_call(
    to="+14155552671",
    from_number="+18005551234",
    agent_id="agent_support_bot"
)

Verify

# Send OTP
verification = orbit.verify.send(
    to="+14155552671",
    channel="sms"
)

# Check OTP
result = orbit.verify.check(
    to="+14155552671",
    code="482901"
)

print(result["data"]["status"])  # "approved"

Webhooks

import hmac
import hashlib

# Flask example
@app.route("/webhooks/orbit", methods=["POST"])
def handle_webhook():
    signature = request.headers.get("X-Devotel-Signature")
    expected = hmac.new(
        b"whsec_your_secret", request.data, hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(signature or "", expected):
        return jsonify({"error": "Invalid signature"}), 401

    event = request.get_json()
    match event["type"]:
        case "message.delivered":
            pass  # Handle delivery
        case "call.completed":
            pass  # Handle call

    return jsonify({"received": True}), 200

Error Handling

from devotel import Devotel, DevotelApiError

try:
    orbit.messages.send(channel="sms", to="invalid", body="Hi")
except DevotelApiError as e:
    print(e.code)     # "INVALID_PHONE_NUMBER"
    print(e.status_code)   # 422
    print(e.message)  # "The to field must be a valid E.164 phone number"

Configuration

OptionTypeDefaultDescription
api_keystrYour Devotel API key (required)
base_urlstrhttps://orbit-api.devotel.io/api/v1API base URL
timeoutfloat30.0Request timeout in seconds

Requirements

  • Python 3.10 or later
  • httpx (installed automatically)