sendio/backend/app/providers/whatsapp_cloud.py
2026-01-13 05:17:57 +02:00

96 lines
3.2 KiB
Python

import httpx
from typing import Dict, Any, Optional
from app.providers.base import BaseProvider
from app.core.config import settings
class WhatsAppCloudProvider(BaseProvider):
"""WhatsApp Cloud API provider (Meta)"""
def __init__(self):
self.access_token = settings.WHATSAPP_CLOUD_ACCESS_TOKEN
self.phone_number_id = settings.WHATSAPP_CLOUD_PHONE_NUMBER_ID
self.base_url = "https://graph.facebook.com/v18.0"
def send_message(
self,
to: str,
template_name: Optional[str],
template_body: str,
variables: Dict[str, str],
language: str = "en"
) -> str:
"""
Send message via WhatsApp Cloud API.
If template_name is provided, sends a template message.
Otherwise, sends a text message.
"""
url = f"{self.base_url}/{self.phone_number_id}/messages"
headers = {
"Authorization": f"Bearer {self.access_token}",
"Content-Type": "application/json"
}
if template_name:
# Send template message
# Build template parameters
components = []
if variables:
parameters = [
{"type": "text", "text": value}
for value in variables.values()
]
components.append({
"type": "body",
"parameters": parameters
})
payload = {
"messaging_product": "whatsapp",
"to": to.replace("+", ""),
"type": "template",
"template": {
"name": template_name,
"language": {
"code": language
},
"components": components
}
}
else:
# Send text message (only for contacts with conversation window)
# Substitute variables in body
message_text = template_body
for key, value in variables.items():
message_text = message_text.replace(f"{{{{{key}}}}}", value)
payload = {
"messaging_product": "whatsapp",
"to": to.replace("+", ""),
"type": "text",
"text": {
"body": message_text
}
}
try:
with httpx.Client(timeout=30.0) as client:
response = client.post(url, headers=headers, json=payload)
response.raise_for_status()
data = response.json()
message_id = data.get("messages", [{}])[0].get("id")
if not message_id:
raise Exception("No message ID in response")
return message_id
except httpx.HTTPStatusError as e:
raise Exception(f"WhatsApp API error: {e.response.status_code} - {e.response.text}")
except Exception as e:
raise Exception(f"Send error: {str(e)}")
def get_provider_name(self) -> str:
return "whatsapp_cloud"