Skip to main content

sage-messaging (Python)

SDK officiel de l'API Sage Messaging : envoi et lecture de messages WhatsApp et SMS, vérification des webhooks.

pip install sage-messaging

Python 3.9+. Client synchrone et asynchrone.

Démarrage

from sage_messaging import SageMessaging

client = SageMessaging(api_key="sk_...")  # ou variable SAGE_MESSAGING_API_KEY

# WhatsApp (canal par défaut)
client.messages.send(phone="+22997000000", message="Bonjour !")

# SMS
client.sms.send(phone="+22997000000", message="Votre code : 4821")

Asynchrone

from sage_messaging import AsyncSageMessaging

async with AsyncSageMessaging() as client:
    await client.messages.send(phone="+22997000000", message="Bonjour !")

Les méthodes sont identiques ; il suffit de les await.

Configuration

Paramètre Variable d'environnement Défaut
api_key SAGE_MESSAGING_API_KEY —
base_url SAGE_MESSAGING_BASE_URL https://messaging.sagecoders.com
webhook_secret SAGE_MESSAGING_WEBHOOK_SECRET —
timeout 30 secondes
max_retries 2 (lectures uniquement)

Les lectures (GET) sont rejouées en cas d'erreur réseau, de 429 ou de 5xx. Les envois ne sont jamais rejoués : un envoi dont la réponse s'est perdue a pu partir, et le rejouer enverrait le message en double.

Envoi

# Message texte, WhatsApp ou SMS
client.messages.send(phone="+229...", message="Salut", channel="sms")

# SMS différé, depuis un téléphone précis
from datetime import datetime, timedelta, timezone
client.sms.send(
    phone="+229...",
    message="Rappel : RDV demain",
    from_="+229...",                          # voir client.sms.phones()
    send_at=datetime.now(timezone.utc) + timedelta(hours=2),  # 20 jours max
)

# Campagne SMS (1 à 100 destinataires)
client.sms.bulk_send(phones=["+229...", "+229..."], message="Promo -20 %")

# Médias WhatsApp (1 à 10, 16 Mo max chacun), envoyés dans l'ordre
res = client.messages.send_media(
    phone="+229...",
    caption="Votre facture",
    media=[
        {"path": "facture.pdf"},                             # fichier local
        {"url": "https://exemple.com/photo.jpg"},            # URL publique
        {"data": image_bytes, "filename": "capture.png"},    # octets
    ],
)
if res["failed"]:  # succès partiel (HTTP 207)
    print("Échecs :", res["failed"])

Utilisez des datetime avec fuseau horaire pour send_at et since.

Lecture

client.conversations.list(unread_only=True, limit=20)
client.conversations.messages(42, direction="received")
client.conversations.mark_read(42)

client.messages.list(after_id=1000)  # flux global, id croissant

Les réponses paginées ont la forme {"data": [...], "meta": {"current_page", "per_page", "total", "last_page"}}.

Suivre les nouveaux messages sans webhook

for msg in client.messages.poll(direction="received", interval=5):
    print(msg["contact_phone"], msg["body"])

Sans after_id, seuls les messages arrivés après l'appel sont renvoyés. Pour reprendre après un redémarrage, conservez le dernier msg["id"] et passez-le en after_id.

Webhooks

Chaque webhook est signé en HMAC-SHA256 (X-Signature, X-Timestamp). Passez le corps brut de la requête, pas un JSON re-sérialisé.

from sage_messaging import verify_webhook, WebhookVerificationError

# FastAPI
@app.post("/webhooks/sage")
async def sage_webhook(request: Request):
    try:
        event = verify_webhook(await request.body(), request.headers, SECRET)
    except WebhookVerificationError:
        raise HTTPException(400)

    if event["event"] == "message.received":
        msg = event["data"]["message"]
        contact = event["data"]["conversation"]
        ...
    return {"ok": True}

Django : verify_webhook(request.body, request.headers, SECRET) ; Flask : verify_webhook(request.get_data(), request.headers, SECRET).

Les requêtes de plus de 5 minutes sont refusées (tolerance=300) pour empêcher leur rejeu.

Erreurs

from sage_messaging import ValidationError, GatewayError, SageMessagingError

try:
    client.sms.send(phone="+229...", message="...")
except ValidationError as e:     # 422 : champ invalide, canal non provisionné…
    print(e.errors, e.channel)
except GatewayError as e:        # 502 : la passerelle a refusé l'envoi
    print(e.detail)
except SageMessagingError as e:  # toutes les autres erreurs du SDK
    print(e)
Classe Cas
AuthenticationError 401 : clé absente ou invalide
PermissionDeniedError 403 : la clé n'a pas la permission requise
NotFoundError 404
ValidationError 422
RateLimitError 429
GatewayError 502 : refus de WhatsApp ou de la passerelle SMS
APIError classe mère des erreurs HTTP (.status, .body)
APIConnectionError réseau, DNS, délai dépassé
WebhookVerificationError signature absente, invalide ou expirée

Permissions des clés API

Permission Méthodes
messages:send messages.send, messages.send_media (WhatsApp)
sms:send sms.* et messages.send(channel="sms")
messages:read messages.list, messages.poll, conversations.*, sms.phones

Release files for sage-messaging 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for sage-messaging 0.1.0
File Size Uploaded
sage_messaging-0.1.0.tar.gz 12.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for sage-messaging 0.1.0
File Interpreter ABI Platform
sage_messaging-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.8 kB

Release files / sage_messaging-0.1.0.tar.gz

Download URL sage_messaging-0.1.0.tar.gz
Size 12.9 kB
Tags Source
SHA-256 checksum
How to use checksums
bc9a91ac4f9ae8737add116b8cb30929b8347c96948ccbd3e4bde8c28a57f1b4
BLAKE2b-256 checksum
How to use checksums
90d24da5e87d866354e3c3f081401c499c18eb3d8712403e10e52e45e38593a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release files / sage_messaging-0.1.0-py3-none-any.whl

Download URL sage_messaging-0.1.0-py3-none-any.whl
Size 15.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
de35f0920e7c872ca6b66e674f8da61c06eb6f89818d8f145ba90a3f9ea820cd
BLAKE2b-256 checksum
How to use checksums
795faa061301689c4273a812508ed50c4ac98da9fe3bcaa3205c97e345c08cbf
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.9

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page