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, media, groups (when the server exposes them), and admin helpers.
- PyPI:
pip install tneenwh— package page: https://pypi.org/project/tneenwh/ - Requirements: Python 3.9+
- HTTP: stdlib only (
urllib) — norequestsdependency
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
- Install
- API base URL
- Setup every script needs
- Configuration API
- Health & authentication
- Account & credentials
- Assistant (dashboard AI)
- Sessions (panel JWT)
- Messaging (default session)
- Channel object (
session(...)) - Sub-API (
x-api-key) - Groups
- OTP helper (no HTTP)
- Not available on stock HTTP mapping
- 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.)
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()
Assistant (dashboard AI)
Server must configure OPENROUTER_API_KEY (or equivalent) for chat to work.
tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...) # panel JWT required
tneenwh.assistant_status()
tneenwh.assistant_chat(message="How do I send media?")
tneenwh.assistant_chat(message="Hello", history=[{"role": "user", "content": "…"}], attachments=[...])
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, 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).
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.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"))
Docs & admin
tneenwh.configure(base_url="https://api.tneenwh.com")
# tneenwh.login(...) # JWT required where route requires auth
tneenwh.openapi_spec()
tneenwh.docs_routes()
tneenwh.admin_users() # admin JWT
tneenwh.admin_sessions()
Not available on stock HTTP mapping
These exist for parity but raise FeatureNotSupportedError unless your server adds routes:
tneenwh.set_status(...) # not mapped on default API
tneenwh.send_list_message(...) # 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.json — GET https://api.tneenwh.com/openapi.json |
Canonical request/response schemas |
MIT License.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tneenwh-0.1.1.tar.gz.
File metadata
- Download URL: tneenwh-0.1.1.tar.gz
- Upload date:
- Size: 15.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b4d8c76e660c06b6654cf6376d15c9f8c256e4b46605354a47d05efd04af6405
|
|
| MD5 |
34a00670ab03ba29ff1dd00fd325a60a
|
|
| BLAKE2b-256 |
d57be1b20272171420f08aa888794a6649b7dfa77f187c2047723de9724f1073
|
File details
Details for the file tneenwh-0.1.1-py3-none-any.whl.
File metadata
- Download URL: tneenwh-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bce1c99858adaf651abcd4ba3588fcfa63c4942cfef73e5c384f57f029ea86dc
|
|
| MD5 |
87e846ec1500fa898c9ca4247583f15b
|
|
| BLAKE2b-256 |
4d642f2f6f0f162bdc9199b14f3ee1868a02098336cd699fa45dc197848037de
|