FastAPI + Celery + Next.js + Postgres/Redis app with company monitoring, source collection, LLM-based change analysis, enrichment, and account security (Turnstile, escalating lockout, email verification).
51 lines
1.9 KiB
Python
51 lines
1.9 KiB
Python
"""Telnyx SMS provider via Telnyx's Programmable Messaging REST API (no SDK
|
|
dependency - just a Bearer-authenticated POST), mirroring twilio_sms.py's
|
|
shape. No-ops with a clear error if Telnyx isn't configured; the caller
|
|
(alert_service) is what additionally gates on `NOTIFICATION_SMS_ENABLED`
|
|
before ever constructing this provider.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import httpx
|
|
|
|
from app.core.config import Settings
|
|
from app.notifications.base import DeliveryResult, NotificationMessage
|
|
|
|
_API_URL = "https://api.telnyx.com/v2/messages"
|
|
|
|
|
|
class TelnyxSmsProvider:
|
|
provider_name = "telnyx_sms"
|
|
|
|
def __init__(self, settings: Settings) -> None:
|
|
self._settings = settings
|
|
|
|
async def send(self, message: NotificationMessage) -> DeliveryResult:
|
|
settings = self._settings
|
|
if not (settings.telnyx_api_key and settings.telnyx_from_number):
|
|
return DeliveryResult(success=False, error="Telnyx is not configured")
|
|
|
|
try:
|
|
async with httpx.AsyncClient(timeout=15) as client:
|
|
response = await client.post(
|
|
_API_URL,
|
|
headers={"Authorization": f"Bearer {settings.telnyx_api_key}"},
|
|
json={
|
|
"from": settings.telnyx_from_number,
|
|
"to": message.destination_value,
|
|
"text": message.body_text,
|
|
},
|
|
)
|
|
except httpx.HTTPError as exc:
|
|
return DeliveryResult(success=False, error=str(exc))
|
|
|
|
data = response.json()
|
|
if response.status_code >= 400:
|
|
errors = data.get("errors") or []
|
|
detail = errors[0].get("detail") if errors else response.text[:200]
|
|
return DeliveryResult(
|
|
success=False, error=f"Telnyx error {response.status_code}: {detail}"
|
|
)
|
|
return DeliveryResult(success=True, external_message_id=data.get("data", {}).get("id"))
|