Skip to main content

Python client for the TNEENWH WhatsApp HTTP API — auth, OTP signup, sessions, messaging.

Project description

tneenwh (Python)

Python client for the TNEENWH WhatsApp HTTP API — authentication, OTP signup, sessions, outbound messaging, webhooks, and groups (when the server exposes them).

The HTTP contract is defined by openapi.json on the API host (e.g. GET https://api.tneenwh.com/openapi.json). Swagger UI is often at /api-docs/.


Table of contents

  1. Install
  2. API base URL
  3. Setup every script needs
  4. Configuration API
  5. Health & authentication
  6. Account & credentials
  7. Sessions (panel JWT)
  8. Messaging (default session)
  9. Channel object (session(...))
  10. Sub-API (x-api-key)
  11. Groups
  12. OTP helper (no HTTP)
  13. Not available on stock HTTP mapping
  14. Errors

Install

pip install tneenwh

From a clone of the TNEENWH repo (editable):

pip install -e ./packages/tneenwh-python

API base URL

Use this deployment as base_url everywhere (no trailing slash):

https://api.tneenwh.com

Use the same host you open in the browser for the dashboard. Paths like /me/... are appended automatically.

Reverse proxies (Cloudflare): If GET /health returns an HTML error or 403 from Cloudflare, set a browser-like user agent:

tneenwh.configure(
    base_url="https://api.tneenwh.com",
    user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
)

(user_agent requires a recent tneenwh package; upgrade if configure rejects the keyword.)


MCP (Model Context Protocol)

TNEENWH exposes MCP (Streamable HTTP) at POST /me/mcp so Cursor / Claude Desktop (and other MCP hosts) can call tools against your deployment.

This package ships small helpers for building the MCP URL and optional focus header:

from tneenwh import panel_mcp_url, mcp_focus_sessions_header

url = panel_mcp_url("https://api.tneenwh.com")  # https://api.tneenwh.com/me/mcp
headers = {"Authorization": "Bearer <panel JWT>"}
headers.update(mcp_focus_sessions_header("session-uuid-1, session-uuid-2"))

Setup every script needs

After import tneenwh, configure the API origin, log in (stores the panel JWT), and bind the WhatsApp session you want to use for send_* and channel helpers:

import tneenwh

tneenwh.configure(base_url="https://api.tneenwh.com")
tneenwh.login(email="you@example.com", password="your-secure-password")

tneenwh.set_session("your-session-uuid", "your-channel-secret-hex")

Get session UUID and channel_secret from the dashboard for that channel. For Sub-API-only flows, set set_api_key(...) from GET /me instead of login() (see Sub-API).


Configuration API

Call Purpose
configure(base_url=..., bearer_token=..., api_key=..., session_id=..., channel_secret=..., user_agent=...) Merge options into global config
get_config() Return current config dataclass
set_base_url(url) API origin
set_bearer_token(token) Panel JWT (Authorization: Bearer)
set_api_key(key) / set_apikey(key) Hex API key for /v1/...
set_session(session_id, channel_secret) Default channel for messaging helpers

Health & authentication

import tneenwh

tneenwh.configure(base_url="https://api.tneenwh.com")

tneenwh.health()  # GET /health — often unauthenticated

tneenwh.signup_send_otp(name="Ada", phone="+10000000000", email="a@b.com", password="SecurePass123")
tneenwh.signup_verify(email="a@b.com", code="123456")
# Aliases: generate_otp(**kwargs), request_signup_otp(**kwargs), verify_otp(email=, code=)

tneenwh.login(email="a@b.com", password="SecurePass123")  # stores JWT in config; returns dict with token
tneenwh.logout()  # POST /auth/logout

Account & credentials

Requires login() first (Bearer token).

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...)  # if not already logged in

tneenwh.me()
tneenwh.profile()
tneenwh.channel_secrets()
tneenwh.rotate_swagger_portal()

Sessions (panel JWT)

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...)

tneenwh.sessions_list()
tneenwh.session_create("My phone")
tneenwh.session_update(session_id, channel_secret, name="Renamed")
tneenwh.session_delete(session_id, channel_secret)
tneenwh.session_disconnect(session_id, channel_secret)
tneenwh.get_channel_secret(session_id)
tneenwh.rotate_channel_secret(session_id, channel_secret)

Messaging (default session)

Call set_session(id, secret) once, or pass session_id= / channel_secret= on each call. (Use base_url="https://api.tneenwh.com".)

Text

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...) ; tneenwh.set_session(...)

tneenwh.send_text("201234567890@c.us", "Hello from Python")

Raw payload (text, media, location, poll, list, options — match OpenAPI ChatSendRequest)

tneenwh.send_message(
    {"to": "201234567890@c.us", "message": "Hi", "options": {"linkPreview": False}},
)

Media (base64, no data: prefix)

import base64

with open("photo.jpg", "rb") as f:
    b64 = base64.standard_b64encode(f.read()).decode("ascii")

tneenwh.send_media(
    "201234567890@c.us",
    mimetype="image/jpeg",
    base64_data=b64,
    caption="Optional caption",
    filename="photo.jpg",
)

QR, status, webhook, inbound queues

Webhook path is always /whatsapp/webhook (e.g. https://api.tneenwh.com/whatsapp/webhook when your HTTPS server uses this host).

Typing indicators (shows “typing…” / “recording…” in the peer’s WhatsApp for ~25s, or clears with stop):

tneenwh.send_chat_state("201234567890@c.us", "typing")       # default session from set_session
tneenwh.send_chat_state("201234567890@c.us", "stop")
tneenwh.v1_send_chat_state("session-uuid", "channel-secret-hex", to="201234567890@c.us", state="typing")
tneenwh.session_status()
tneenwh.session_details()
tneenwh.session_qr()
tneenwh.refresh_session_qr()

tneenwh.session_incoming()
tneenwh.session_events()
tneenwh.session_calls()

tneenwh.set_webhook("https://api.tneenwh.com/whatsapp/webhook", ["message", "message_create"])

raw_bytes, content_type = tneenwh.download_inbound_media("hex-ticket-from-webhook")

Channel object (session(...))

Bound calls for one session without relying on global set_session:

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...)  # panel JWT required for /me/sessions/...

ch = tneenwh.session("session-uuid", "channel-secret-hex")

ch.status()
ch.details()
ch.qr()
ch.refresh_qr()
ch.set_webhook("https://api.tneenwh.com/whatsapp/webhook", ["message"])

ch.incoming()
ch.events()
ch.calls()

data, ctype = ch.download_inbound_media("ticket")

ch.send_text("201234567890@c.us", "Hi")
ch.send_message({"to": "…@c.us", "message": "x"})
ch.send_media("…@c.us", mimetype="image/png", base64_data=b64, caption="…")
ch.send_list_message(
    "201234567890@c.us",
    button_text="Choose",
    sections=[{"title": "Menu", "rows": [{"id": "a", "title": "Option A"}]}],
)

ch.get_channel_secret()
ch.rotate_channel_secret()

Sub-API (x-api-key)

Use when you only have API key + channel secret (no browser JWT). Set the key from GET /me (apiKey field).

import tneenwh

tneenwh.configure(base_url="https://api.tneenwh.com")
tneenwh.set_api_key("hex-api-key-from-me")

tneenwh.v1_sessions_list()

tneenwh.v1_send_message(
    "session-uuid",
    "channel-secret-hex",
    {"to": "201234567890@c.us", "message": "Hello via v1"},
)

Groups

All group helpers require set_session (or session_id / channel_secret kwargs). Availability depends on your server exposing WhatsApp group routes.

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...) ; tneenwh.set_session(...)

tneenwh.create_group("Team chat", participants=["201...@c.us"])

tneenwh.group_get("120...@g.us")
tneenwh.group_participants_add("120...@g.us", ["201...@c.us"])
tneenwh.group_participants_remove("120...@g.us", ["201...@c.us"])
tneenwh.group_admins_promote("120...@g.us", ["201...@c.us"])
tneenwh.group_admins_demote("120...@g.us", ["201...@c.us"])

tneenwh.group_set_subject("120...@g.us", "New title")
tneenwh.group_set_description("120...@g.us", "About text")

tneenwh.group_invite_code("120...@g.us")
tneenwh.group_revoke_invite("120...@g.us")
tneenwh.group_leave("120...@g.us")

tneenwh.group_set_add_members_admins_only("120...@g.us", True)
tneenwh.group_set_messages_admins_only("120...@g.us", True)
tneenwh.group_set_info_admins_only("120...@g.us", True)

tneenwh.group_set_picture("120...@g.us", mimetype="image/jpeg", base64_data=b64)
tneenwh.group_delete_picture("120...@g.us")

tneenwh.group_membership_requests("120...@g.us")
tneenwh.group_membership_approve("120...@g.us", body={})
tneenwh.group_membership_reject("120...@g.us", body={})

OTP helper (no HTTP)

Build the OTP message text for send_text (not the signup HTTP OTP):

from tneenwh import format_otp_notification_message, OtpNotificationParams

text = format_otp_notification_message(OtpNotificationParams(code="123456", brand="MyApp"))

Not available on stock HTTP mapping

Only status/profile advanced calls remain unsupported on stock mapping:

tneenwh.set_status(...)           # not mapped on default API

Errors

import tneenwh
from tneenwh import TneenwhApiError, FeatureNotSupportedError

tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...) ; tneenwh.set_session(...)

try:
    tneenwh.send_text("201234567890@c.us", "Hi")
except FeatureNotSupportedError as e:
    print("Unsupported:", e.feature)
except TneenwhApiError as e:
    print(e.status, e.body)  # JSON body when present
    if e.is_unauthorized():
        ...

Helpers: is_api_error(exc), is_feature_not_supported(exc). See TneenwhApiError predicate methods on the exception instance (is_config_or_transport_error, is_bad_request, …).


More documentation

Doc Content
Repo docs/TNEENWH-LIBRARY-REFERENCE.md Full parity tables, TypeScript mirror, error catalog
Repo docs/TNEENWH-SDK.md Short onboarding
openapi.jsonGET https://api.tneenwh.com/openapi.json Canonical request/response schemas

MIT License.

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

tneenwh-0.1.7.tar.gz (16.9 kB view details)

Uploaded Source

Built Distribution

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

tneenwh-0.1.7-py3-none-any.whl (15.6 kB view details)

Uploaded Python 3

File details

Details for the file tneenwh-0.1.7.tar.gz.

File metadata

  • Download URL: tneenwh-0.1.7.tar.gz
  • Upload date:
  • Size: 16.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for tneenwh-0.1.7.tar.gz
Algorithm Hash digest
SHA256 5199d6d23088edcb6b79297efdce4855393aa98628be67fd5027c6bed12079b6
MD5 97b0794f3807e2cc6ded2aef3418307b
BLAKE2b-256 eb0ecb2fddcc62ed68c1e7b5a81259a9fef9a8b54dcec05d2541e4c9e9b5b58a

See more details on using hashes here.

File details

Details for the file tneenwh-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: tneenwh-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 15.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.4

File hashes

Hashes for tneenwh-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 2255a263260c256495035d40b7115c310cc810a2f208d9620a15a7abd41dd282
MD5 2a41cf48e6861b1635a08d0308d84d31
BLAKE2b-256 cf83b6a5ce3c17f97292551d3f7dfe74aa57c9fbf29192cffe13ecae3e3fe22a

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