Skip to main content

EnvoiSMS Python SDK

PyPI version Python versions License: MIT

Official Python SDK for EnvoiSMS.ma — the direct-operator SMS, WhatsApp Business (WABA) and OTP verification API platform for Morocco (Maroc). One client, one API key, four channels.

pip install envoisms

What is EnvoiSMS.ma?

EnvoiSMS.ma routes transactional and marketing messages through direct connections to Morocco's three mobile operators, plus the official WhatsApp Cloud API — no aggregator, no gray SIM routes.

Channel What it's for Covered by this SDK
SMS Direct Opérateurs — IAM, Inwi, Orange OTP codes, delivery alerts, marketing SMS, from 0.48 MAD/SMS ✅ send(), send_bulk()
WhatsApp Business API (Meta WABA) Approved templates, interactive buttons, catalog, multi-agent inbox, from 0.65 MAD/message ✅ send(channel="whatsapp")
OTP / 2FA Verification Send + check one-time codes over SMS or WhatsApp ✅ send_otp(), check_otp()
Numéro Virtuel (+212) Cloud Moroccan business line, no physical SIM, shared team inbox Manage from the dashboard
Assistant IA Conversationnel Darija/French AI agent for COD order confirmation & support handoff Manage from the dashboard

Numéros Virtuels and the AI assistant are configured from your EnvoiSMS.ma dashboard today; dedicated SDK endpoints for them are on the roadmap. Everything below (send, OTP, billing, webhooks) works with the SDK right now.

Quick Start — Send an SMS

import os
from envoisms import EnvoiSMSClient

client = EnvoiSMSClient(api_key=os.getenv("ENVOISMS_API_KEY"))

response = client.send(
    to="+212600000000",
    message="Votre code de vérification est 492018",
    from_sender="MonBusiness",  # validated Sender ID, or omit to use your default
)

print(f"Message ID: {response['id']}")

Send a WhatsApp Business Message

Same client, same method — just switch the channel. Requires WhatsApp connected in your dashboard.

response = client.send(
    to="+212600000000",
    message="Bonjour ! Votre commande #89240 a été expédiée.",
    channel="whatsapp",
)

Automatic channel fallback (cascade)

Send over WhatsApp and drop back to SMS automatically when a number is unreachable or has no WhatsApp — the same fallback used for VTC riders on flaky mobile data.

response = client.send(
    to="+212600000000",
    message="Votre chauffeur arrive dans 2 minutes.",
    channel="whatsapp",
    cascade=True,
)

OTP / 2FA Verification

# 1. Send OTP (channel="sms" by default; pass channel="whatsapp" to send over WhatsApp instead)
otp_res = client.send_otp(
    to="+212600000000",
    brand="MonBusiness",
    code_length=6,
    expiry=600,  # seconds
)

session_id = otp_res["session_id"]

# 2. Verify the code the user typed in
check_res = client.check_otp(session_id=session_id, code="492018")

if check_res.get("verified"):
    print("OTP code is valid!")

# Optional: inspect a session's status without consuming an attempt
session = client.get_otp_session(session_id)

Bulk Sending

client.send_bulk(
    messages=[
        {"to": "+212600000001", "message": "Promo -20% ce week-end"},
        {"to": "+212600000002", "message": "Promo -20% ce week-end"},
    ],
    from_sender="MonBusiness",
)

Message Status & Delivery

status = client.get_message(message_id="msg_123")
recent = client.list_messages(limit=50, offset=0)

Verifying Delivery Webhooks (DLR)

If you configure a delivery-status webhook, verify its X-EnvoiSMS-Signature header before trusting the payload:

from envoisms import EnvoiSMSClient

is_valid = EnvoiSMSClient.verify_webhook_signature(
    raw_body=request.body,             # raw request bytes/string, not parsed JSON
    signature_header=request.headers["X-EnvoiSMS-Signature"],
    secret=os.getenv("ENVOISMS_WEBHOOK_SECRET"),
)

Account & Billing

balance = client.get_balance()
packs = client.list_packs()
payment_methods = client.list_payment_methods()

client.create_topup(amount_mad=200, payment_method="stripe")

Analytics & API Keys

stats = client.analytics(days=30)
new_key = client.create_api_key(name="Server key", scope="live")

Compliance: Opt-outs (STOP)

client.create_optout(phone="+212600000000")

Error Handling & Retries

The client retries 5xx responses and network errors up to max_retries times (default 2) with exponential backoff, and raises EnvoiSMSError — with status_code and code attributes — on any failure:

from envoisms import EnvoiSMSClient, EnvoiSMSError

client = EnvoiSMSClient(api_key=os.getenv("ENVOISMS_API_KEY"), max_retries=3, timeout=20)

try:
    client.send(to="+212600000000", message="Test")
except EnvoiSMSError as e:
    print(f"Send failed ({e.status_code} {e.code}): {e}")

Why teams pick EnvoiSMS.ma over an aggregator

  • Direct routes to IAM, Inwi and Orange — no international transit hop, no gray-route ban risk.
  • Sub-2-second OTP latency, measured — aggregators routing through Europe typically land in the 10s+ range.
  • Billing in MAD, no EUR/USD conversion surprises.
  • Local support based in Casablanca, not an offshore ticket queue.

See the full breakdown on envoisms.ma.

Documentation & Pricing

Other official SDKs

Support

License

MIT

Release files for envoisms 1.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 envoisms 1.1.0
File Size Uploaded
envoisms-1.1.0.tar.gz 7.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for envoisms 1.1.0
File Interpreter ABI Platform
envoisms-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 15.3 kB

Release files / envoisms-1.1.0.tar.gz

Download URL envoisms-1.1.0.tar.gz
Size 7.8 kB
Tags Source
SHA-256 checksum
How to use checksums
921e0bb3d9ecdc8c0fc9f4e5e3e64f6c036769a39e28034d4f8c80c7d1574787
BLAKE2b-256 checksum
How to use checksums
77ec3115ffc1c95b051d0818151789e8843d088e5e32e922938bb8b036fe37d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release files / envoisms-1.1.0-py3-none-any.whl

Download URL envoisms-1.1.0-py3-none-any.whl
Size 7.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
28bdf47ac081131d212ab5e5b3e453da144321ffe81b4d5b87a55089099c0c36
BLAKE2b-256 checksum
How to use checksums
72505cc6aa878556ddff43fd2287cc795231891d0adde381155e5f52d6086ca7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.6

Release history Release notifications | RSS feed

1.2.0

2 release files

This release

1.1.0 This release

2 release files

1.0.0

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