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.1.0.tar.gz (14.9 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.1.0-py3-none-any.whl (19.0 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for waotomatis-0.1.0.tar.gz
Algorithm Hash digest
SHA256 67d038835ce6f151e41fda4b90ab8cac7c8362bedbeca56397a868c4538d1084
MD5 28f8745e8ca4300eaa1fd028b480be1b
BLAKE2b-256 37554615c407b2a480a9b9bbc89a3c73fe5b98e0c92cb1e0ede10562ae399021

See more details on using hashes here.

File details

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

File metadata

  • Download URL: waotomatis-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 19.0 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.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3d49080b16209960721bdbb64f1aa95e9ec8bcc39584d872fd855a924a315f5b
MD5 ab0457d5cedd97e221463ce3f9665690
BLAKE2b-256 79b90a3f3d8f52621fc9bcdab83e8cd042dd8d1dffc4e730f35ba51355edabb8

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