wotp 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,146 @@
1
+ Metadata-Version: 2.4
2
+ Name: wotp
3
+ Version: 1.0.0
4
+ Summary: Official Python SDK for Wotp — WhatsApp OTP, self-hosted, one command.
5
+ Project-URL: Homepage, https://github.com/wotp/wotp
6
+ Project-URL: Documentation, https://github.com/wotp/wotp
7
+ Project-URL: Repository, https://github.com/wotp/wotp
8
+ Author: Wotp
9
+ License-Expression: MIT
10
+ Keywords: 2fa,auth,otp,verification,whatsapp,wotp
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.10
21
+ Requires-Dist: httpx>=0.27.0
22
+ Requires-Dist: pydantic>=2.0.0
23
+ Description-Content-Type: text/markdown
24
+
25
+ # wotp
26
+
27
+ Official Python SDK for **Wotp** — WhatsApp OTP, self-hosted, one command.
28
+
29
+ [![PyPI](https://img.shields.io/pypi/v/wotp)](https://pypi.org/project/wotp/)
30
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install wotp
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ```python
41
+ from wotp import create_client
42
+
43
+ client = create_client("http://localhost:54321", "wotp_anon_xxx")
44
+
45
+ # Send an OTP
46
+ resp = client.send_otp("+212600000000")
47
+ print(f"Token: {resp.token}, expires at: {resp.expires_at}")
48
+
49
+ # Verify the code entered by the user
50
+ result = client.verify_otp(resp.token, "483920")
51
+
52
+ # Send a text message
53
+ text_res = client.send_text("+212600000000", "Hello world")
54
+
55
+ # Send a media message
56
+ media_res = client.send_media("+212600000000", url="https://example.com/image.png")
57
+
58
+ # List chats
59
+ chats = client.get_chats()
60
+
61
+ print(f"Verified: {result.verified}")
62
+ ```
63
+
64
+ ## API Reference
65
+
66
+ ### `create_client(url, api_key, **options)`
67
+
68
+ Creates a new Wotp client instance.
69
+
70
+ | Parameter | Type | Description |
71
+ |-----------|------|-------------|
72
+ | `url` | `str` | Base URL of your Wotp instance |
73
+ | `api_key` | `str` | Your anon or service API key |
74
+ | `max_retries` | `int` | Max retries on transient errors (default: `3`) |
75
+ | `retry_delay` | `float` | Base delay in seconds between retries (default: `0.5`) |
76
+ | `timeout` | `float` | Request timeout in seconds (default: `10.0`) |
77
+
78
+ ### `client.send_otp(phone)`
79
+
80
+ Send an OTP to the given phone number.
81
+
82
+ - **Parameters:** `phone` — E.164 formatted phone number
83
+ - **Returns:** `SendOTPResponse` with `.token` and `.expires_at`
84
+ - **Raises:** `RateLimitError`
85
+
86
+ ### `client.verify_otp(token, code)`
87
+
88
+ Verify an OTP code against a previously issued token.
89
+
90
+ - **Parameters:** `token` — from `send_otp`, `code` — the user-entered code
91
+ - **Returns:** `VerifyOTPResponse` with `.verified`, `.phone`, `.attempts_remaining`
92
+ - **Raises:** `ExpiredTokenError`, `InvalidCodeError`
93
+
94
+ ### `client.health()`
95
+
96
+ Check the health of the Wotp instance.
97
+
98
+ - **Returns:** `HealthResponse` with `.status`, `.phone`, `.uptime_seconds`
99
+
100
+ ## Error Handling
101
+
102
+ The SDK raises typed exceptions for business failures:
103
+
104
+ ```python
105
+ from wotp import create_client, RateLimitError, ExpiredTokenError, InvalidCodeError
106
+
107
+ client = create_client("http://localhost:54321", "wotp_anon_xxx")
108
+
109
+ try:
110
+ result = client.verify_otp(token, code)
111
+ except RateLimitError as e:
112
+ print(f"Rate limited. Retry after {e.retry_after}s")
113
+ except ExpiredTokenError:
114
+ print("Token expired — request a new OTP")
115
+ except InvalidCodeError as e:
116
+ print(f"Wrong code. {e.attempts_remaining} attempts left")
117
+ ```
118
+
119
+ | Exception | When |
120
+ |-----------|------|
121
+ | `RateLimitError` | Phone/IP exceeded rate limit (HTTP 429) |
122
+ | `ExpiredTokenError` | Token has expired (HTTP 410 or `expired_token`) |
123
+ | `InvalidCodeError` | Wrong OTP code (HTTP 400 + `invalid_code`) |
124
+ | `WotpError` | Base class for all SDK errors |
125
+
126
+ ## Context Manager
127
+
128
+ The client can be used as a context manager to ensure proper cleanup:
129
+
130
+ ```python
131
+ with create_client("http://localhost:54321", "wotp_anon_xxx") as client:
132
+ resp = client.send_otp("+212600000000")
133
+ ```
134
+
135
+ ## Auto-Retry
136
+
137
+ Transient errors (502, 503, 504, network timeouts) are automatically retried with exponential backoff. Business errors are **never** retried.
138
+
139
+ ## Requirements
140
+
141
+ - Python ≥ 3.10
142
+ - A running Wotp instance
143
+
144
+ ## License
145
+
146
+ MIT — see [LICENSE](../../LICENSE) for details.
@@ -0,0 +1,3 @@
1
+ wotp-1.0.0.dist-info/METADATA,sha256=ayw-DDLYLQavXHLVElEMu8k3nNmA_vcVmCO-a4veRak,4378
2
+ wotp-1.0.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
3
+ wotp-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any