Skip to main content

Official Python SDK for WAOtomatis — headless WhatsApp (WABA Cloud API).

Project description

waotomatis

Official Python SDK for WAOtomatis — headless WhatsApp infrastructure on the WhatsApp Business Platform (WABA Cloud API). Send messages, upload media, list chats and contacts, register webhooks, and verify webhook signatures.

  • Zero dependencies. Pure standard library (urllib, hmac, hashlib).
  • Python 3.8+. Type-hinted, py.typed.
  • Idiomatic. snake_case methods, keyword arguments, a typed error hierarchy.

Install

pip install waotomatis

Quickstart

import os
from waotomatis import Waotomatis

wao = Waotomatis(api_key=os.environ["WAO_API_KEY"])

msg = wao.sessions("sess_123").messages.send(
    to="628123456789",
    type="text",
    text="Halo dari WAOtomatis 👋",
)

print(msg["id"])  # msg_abc123

Waotomatis defaults to https://api.waotomatis.com; pass base_url=... to override. The API key is sent as Authorization: Bearer <api_key>.

Sending messages

session = wao.sessions("sess_123")

# Text (optionally with a link preview)
session.messages.send(to="628123456789", type="text", text="Hi", preview_url=True)

# Image by public link, or by an uploaded media id
session.messages.send(to="628...", type="image", link="https://example.com/a.jpg",
                      caption="Hello")
session.messages.send(to="628...", type="image", media_id="media_abc")

# Document with a filename
session.messages.send(to="628...", type="document", media_id="media_abc",
                      file_name="invoice.pdf")

# Audio as a voice note
session.messages.send(to="628...", type="audio", media_id="media_abc", voice=True)

# Idempotent send (safe to retry — the same key returns the original result)
session.messages.send(to="628...", type="text", text="hi",
                      idempotency_key="order-42")

# Mark an inbound message read by its provider wamid
session.messages.mark_read("wamid.HBg...")

Media

session = wao.sessions("sess_123")

# Upload raw bytes
with open("photo.jpg", "rb") as f:
    res = session.media.upload(f.read(), file_name="photo.jpg", mime_type="image/jpeg")
print(res["mediaId"])

# Or upload a local file by path
res = session.media.upload_file("photo.jpg", mime_type="image/jpeg")

# Or upload by URL
res = session.media.upload_from_url("https://example.com/photo.jpg")

# Download inbound media bytes
data, mime_type = session.media.download("media_abc")

Sessions, chats, and contacts

# List sessions (one page)
page = wao.list_sessions()
for s in page:
    print(s["id"], s["status"])

session = wao.sessions("sess_123")
session.get()
session.delete()  # disconnect

# Chats and contacts auto-paginate — iterate every item across all pages
for chat in session.chats.list():
    print(chat["chatId"], chat.get("lastText"))

for message in session.chats.history("628123456789"):
    print(message["direction"], message["type"])

for contact in session.contacts.list():
    print(contact["waId"], contact.get("name"))

# Or grab just one page
first = session.contacts.list(limit=50).first_page()
print(len(first), first.has_more, first.cursor)

contact = session.contacts.get("628123456789")

Webhooks

Register a webhook — the signing secret is returned once:

hook = wao.sessions("sess_123").webhooks.create(
    url="https://example.com/webhook",
    events=["message.received", "message.updated", "session.status"],
)
secret = hook["secret"]  # store this

Verify and parse incoming deliveries. The server signs the exact raw request body with HMAC-SHA256 and sends it in the X-Wao-Signature: sha256=<hex> header. Verify against the raw bytes you received — never a re-serialized object:

from waotomatis import construct_event, verify_webhook, WaotomatisError

# Just verify
ok = verify_webhook(raw_body, request.headers.get("X-Wao-Signature"), secret)

# Verify + parse (raises on a bad signature or unparseable body)
try:
    event = construct_event(raw_body, request.headers.get("X-Wao-Signature"), secret)
except WaotomatisError:
    return ("", 401)

if event["event"] == "message.received":
    print(event["data"]["text"])

Flask example

import os
from flask import Flask, request, abort
from waotomatis import construct_event, WaotomatisError, WEBHOOK_SIGNATURE_HEADER

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["WAO_WEBHOOK_SECRET"]

@app.post("/webhook")
def webhook():
    try:
        event = construct_event(
            request.get_data(),  # raw bytes
            request.headers.get(WEBHOOK_SIGNATURE_HEADER),
            WEBHOOK_SECRET,
        )
    except WaotomatisError:
        abort(401)
    # handle event...
    return ("", 200)

Errors

Every failure raises a subclass of WaotomatisError, carrying the stable code, message, request_id, and HTTP status from the server's uniform error model ({"error": {"code", "message", "requestId"}}).

from waotomatis import (
    Waotomatis, WaotomatisError,
    AuthenticationError, PermissionError, NotFoundError,
    ValidationError, RateLimitError, ApiError,
    ConnectionError, TimeoutError,
)
import time

try:
    wao.sessions("sess_123").messages.send(to="628...", type="text", text="hi")
except RateLimitError as e:
    time.sleep(e.retry_after or 1)
except WaotomatisError as e:
    if e.code == "session_disconnected":
        ...
    print(e.code, e.status, e.request_id)
Exception HTTP
AuthenticationError 401
PermissionError 403
NotFoundError 404
TimeoutError 408 / local
ValidationError 409 / 422
RateLimitError 429
ApiError 5xx
ConnectionError network

Transient failures (408/429/5xx/network) on idempotent verbs — or any call given an idempotency_key — are retried automatically with exponential backoff and jitter, honoring Retry-After. Tune with max_retries= and timeout= on the constructor.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

waotomatis-0.2.0.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

waotomatis-0.2.0-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

File details

Details for the file waotomatis-0.2.0.tar.gz.

File metadata

  • Download URL: waotomatis-0.2.0.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for waotomatis-0.2.0.tar.gz
Algorithm Hash digest
SHA256 c57a77539288756fcc64da5c368f2cf1e68190478ff19266aa2b8c7342301a76
MD5 7f4e79e9a56edcf80c3d10e8e14f63ab
BLAKE2b-256 04e689024435f152befeae846e77de895c72e22e01c132085b39ea8458f516d6

See more details on using hashes here.

File details

Details for the file waotomatis-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: waotomatis-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 19.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.6

File hashes

Hashes for waotomatis-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 86f1fa966d3efd3c4d0b6eac7bf12e396a3af701659f0601a7ffe4a22ff97f2b
MD5 6fe5f0fdd3aa5e746ad8472e52852ffe
BLAKE2b-256 007827d07fdd24ef542097094ae95f9dd3e631a393dabf422ae039c07baae408

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page