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, media, groups (when the server exposes them), and admin helpers.

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. Assistant (dashboard AI)
  8. Sessions (panel JWT)
  9. Messaging (default session)
  10. Channel object (session(...))
  11. Sub-API (x-api-key)
  12. Groups
  13. OTP helper (no HTTP)
  14. Not available on stock HTTP mapping
  15. 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.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.1.tar.gz (15.7 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.1-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

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

Hashes for tneenwh-0.1.1.tar.gz
Algorithm Hash digest
SHA256 b4d8c76e660c06b6654cf6376d15c9f8c256e4b46605354a47d05efd04af6405
MD5 34a00670ab03ba29ff1dd00fd325a60a
BLAKE2b-256 d57be1b20272171420f08aa888794a6649b7dfa77f187c2047723de9724f1073

See more details on using hashes here.

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

Hashes for tneenwh-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bce1c99858adaf651abcd4ba3588fcfa63c4942cfef73e5c384f57f029ea86dc
MD5 87e846ec1500fa898c9ca4247583f15b
BLAKE2b-256 4d642f2f6f0f162bdc9199b14f3ee1868a02098336cd699fa45dc197848037de

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