Python SDK Planned
Idiomatic Python wrapper for the message.com REST API. Pythonic naming (snake_case), typed dataclasses, sync and async clients, retries with exponential backoff. Targets Python 3.10+ and is type-checked with mypy strict.
Scheduled for Q2 2026. The underlying REST endpoints are already live and stable, so backend integrations can be built today against raw HTTP. See the REST API conventions for the manual approach.
Installation
The package supports CPython 3.10 through 3.13 plus PyPy 3.10. We avoid native dependencies so wheels are platform-agnostic.
pip install message-com
# or, if you use uv
uv pip install message-com
# poetry
poetry add message-comInitialise the client
Construct a single client per process. The client is thread-safe and connection-pooled. For high-throughput backends, share one instance across workers.
import os
from message_com import Message
msg = Message(api_key=os.environ["MESSAGE_API_KEY"])Sync visitors
The most common backend task is mirroring your customer table into the workspace visitor list. The SDK exposes an idempotent visitors.upsert that keys on external_id first, then falls back to email.
# Upsert a visitor on a Django signal
msg.visitors.upsert(
email="[email protected]",
external_id="crm-4567",
name="Alice Johnson",
attributes={"plan": "pro", "mrr": 99},
)Create tickets
Tickets are conversations where channel = "ticket". The helper hides that detail. A reply on the resulting ticket sends as email through your configured outbound domain.
# Open a ticket from a Celery task
msg.tickets.create(
visitor_email="[email protected]",
subject="Auto-detected failed payment",
body="Stripe charge ch_xyz failed. Reach out within 4h.",
tags=["billing", "auto-created"],
)Async client
The async variant exposes the same surface using httpx under the hood. Use it from FastAPI, Starlette, or any asyncio runtime.
import asyncio
from message_com import AsyncMessage
async def main():
async with AsyncMessage(api_key="msg_live_...") as msg:
async for conv in msg.conversations.stream(status="open"):
print(conv.id, conv.subject)
asyncio.run(main())Framework integrations
The Python SDK ships first-party adapters for the major frameworks. These thin wrappers handle settings discovery, lifecycle hooks, and error propagation.
- Django. Add to
INSTALLED_APPS, runpython manage.py message_syncto backfill, then point yourpost_savesignals at the helper. - Flask.
MessageFlask(app)binds the client toapp.extensionsand reads config fromapp.config. - FastAPI. Use the dependency-injection helper to get a per-request handle.
Retries and timeouts
The client retries on 429 and 5xx responses with jittered exponential backoff, capped at five attempts. You can override the retry policy per call or globally on the constructor.
Common pitfalls
- Do not call from request handlers without timeouts. The default network timeout is 30s. Set
timeout=5on hot paths. - Use
external_idfor stable identity. Visitors change emails; primary keys do not. - Keep one client per process, not per request. The HTTP connection pool is the expensive part.