connect24 0.1.0__tar.gz

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,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ # The floor and the current release. A library is installed into applications whose Python
15
+ # version nobody consulted us about, so both ends have to stay green.
16
+ python: ['3.9', '3.13']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python }}
24
+
25
+ - run: pip install pytest
26
+ - run: python -m pytest tests -q
27
+ env:
28
+ PYTHONPATH: src
@@ -0,0 +1,40 @@
1
+ name: Publish to PyPI
2
+
3
+ # Tag-driven, so a release is a deliberate act with a name rather than whatever happened to land
4
+ # on main. Tag as v0.1.0 and the version in pyproject.toml must match — the job checks.
5
+ on:
6
+ push:
7
+ tags: ['v*']
8
+
9
+ jobs:
10
+ publish:
11
+ runs-on: ubuntu-latest
12
+ environment: pypi
13
+
14
+ permissions:
15
+ # The whole point of trusted publishing: GitHub mints a short-lived OIDC token for this run
16
+ # and PyPI verifies it came from this repo and this workflow. There is no API token to store,
17
+ # rotate, or leak — which is the only kind of secret that cannot be stolen from a CI log.
18
+ id-token: write
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - uses: actions/setup-python@v5
24
+ with:
25
+ python-version: '3.12'
26
+
27
+ - name: Refuse a tag that disagrees with the package version
28
+ run: |
29
+ TAG="${GITHUB_REF_NAME#v}"
30
+ VERSION=$(grep -m1 '^version' pyproject.toml | cut -d'"' -f2)
31
+ if [ "$TAG" != "$VERSION" ]; then
32
+ echo "Tag $GITHUB_REF_NAME does not match version $VERSION in pyproject.toml." >&2
33
+ exit 1
34
+ fi
35
+ echo "Publishing $VERSION"
36
+
37
+ - run: pip install build
38
+ - run: python -m build
39
+
40
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ dist/
4
+ build/
5
+ *.egg-info/
6
+ .pytest_cache/
7
+ .mypy_cache/
8
+ .ruff_cache/
9
+ .venv/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Connect24
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,213 @@
1
+ Metadata-Version: 2.5
2
+ Name: connect24
3
+ Version: 0.1.0
4
+ Summary: Official Python client for the Connect24 communications API — email, SMS and WhatsApp.
5
+ Project-URL: Homepage, https://connect24.co.za
6
+ Project-URL: Documentation, https://connect24.co.za/developer
7
+ Project-URL: Source, https://github.com/Lihle2018/connect24-python
8
+ Author: Connect24
9
+ License: MIT License
10
+
11
+ Copyright (c) 2026 Connect24
12
+
13
+ Permission is hereby granted, free of charge, to any person obtaining a copy
14
+ of this software and associated documentation files (the "Software"), to deal
15
+ in the Software without restriction, including without limitation the rights
16
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
+ copies of the Software, and to permit persons to whom the Software is
18
+ furnished to do so, subject to the following conditions:
19
+
20
+ The above copyright notice and this permission notice shall be included in all
21
+ copies or substantial portions of the Software.
22
+
23
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29
+ SOFTWARE.
30
+ License-File: LICENSE
31
+ Keywords: connect24,email,messaging api,popia,sms,sms api,south africa,whatsapp
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: License :: OSI Approved :: MIT License
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.9
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Programming Language :: Python :: 3.13
41
+ Classifier: Topic :: Communications
42
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
43
+ Classifier: Typing :: Typed
44
+ Requires-Python: >=3.9
45
+ Provides-Extra: dev
46
+ Requires-Dist: mypy>=1.8; extra == 'dev'
47
+ Requires-Dist: pytest>=7; extra == 'dev'
48
+ Requires-Dist: ruff>=0.4; extra == 'dev'
49
+ Description-Content-Type: text/markdown
50
+
51
+ # Connect24 Python SDK
52
+
53
+ Official Python client for the [Connect24](https://connect24.co.za) communications API —
54
+ one interface for email, SMS and WhatsApp.
55
+
56
+ ```bash
57
+ pip install connect24
58
+ ```
59
+
60
+ No runtime dependencies. An SDK is a dependency of *your* application, and every package it drags
61
+ in is a version conflict that becomes yours to resolve.
62
+
63
+ ## Quick start
64
+
65
+ Get your **account id** and an **API key** from the portal, under Settings → API keys.
66
+
67
+ ```python
68
+ import os
69
+ from connect24 import Connect24
70
+
71
+ client = Connect24(
72
+ account_id="acc_3f9c1a7b4e2d",
73
+ api_key=os.environ["CONNECT24_API_KEY"],
74
+ )
75
+
76
+ client.messages.send_sms("+27821234567", "Your payment is due tomorrow.")
77
+ ```
78
+
79
+ Or read both from the environment, which is what most deployments want:
80
+
81
+ ```python
82
+ client = Connect24.from_env() # CONNECT24_ACCOUNT_ID, CONNECT24_API_KEY
83
+ ```
84
+
85
+ ## What you can reach
86
+
87
+ | | |
88
+ |---|---|
89
+ | `client.messages` | Send email, SMS and WhatsApp; read status and history |
90
+ | `client.templates` | Stored bodies with placeholders, so copy lives on the platform |
91
+ | `client.suppressions` | Addresses that will not be sent to |
92
+ | `client.webhooks` | Delivery events pushed to you, plus signature verification |
93
+ | `client.sending_domains` | Prove you control a domain, so mail goes out as you |
94
+ | `client.billing` | Prepaid credit, pricing and the statement |
95
+ | `client.account` | Who you are, and which channels can send right now |
96
+
97
+ ## Every channel, one shape
98
+
99
+ ```python
100
+ # SMS
101
+ client.messages.send_sms("+27821234567", "Your delivery is on its way.")
102
+
103
+ # WhatsApp — free-form inside the 24-hour window, a template outside it
104
+ client.messages.send_whatsapp("+27821234567", "Your order has shipped.")
105
+ client.messages.send_whatsapp("+27821234567", template_name="payment_reminder")
106
+
107
+ # Email
108
+ client.messages.send_email(
109
+ to="customer@example.com",
110
+ subject="Payment reminder",
111
+ html="<p>Your account is overdue.</p>",
112
+ sender={"address": "collections@acme.co.za", "name": "Acme Collections"},
113
+ )
114
+ ```
115
+
116
+ ## Two things that surprise people
117
+
118
+ **Your `sender` address is not used until you verify the domain.** Until then mail leaves from your
119
+ account's assigned address on `connect24.co.za` and yours becomes the Reply-To. Verify with
120
+ `client.sending_domains.add("acme.co.za")`, publish the returned DNS records, then `verify`.
121
+
122
+ **There is no sender for SMS.** South African traffic routes from a shared originator pool, and
123
+ naming an identity you do not own is rejected by the network.
124
+
125
+ ## Not sending twice
126
+
127
+ Pass an idempotency key when a network failure leaves you unsure whether a send arrived. A repeat
128
+ with the same key returns the original message instead of sending again:
129
+
130
+ ```python
131
+ client.messages.send_sms(
132
+ "+27821234567",
133
+ "Your order has shipped.",
134
+ idempotency_key=f"order-{order.id}-shipped",
135
+ )
136
+ ```
137
+
138
+ Use something stable and tied to the event — an order id, not a UUID generated at call time, which
139
+ would differ on the retry and defeat the point.
140
+
141
+ ## Watch the emoji
142
+
143
+ An SMS holds 160 characters using the GSM-7 alphabet. A single emoji, curly quote or em dash
144
+ switches the whole message to UCS-2, which holds 70 characters per part. A 150-character message
145
+ with one emoji costs **three** SMS, not one. The portal shows the segment count while you write.
146
+
147
+ ## Verifying a webhook
148
+
149
+ Verify against the **raw body**, before any framework parses it.
150
+
151
+ ```python
152
+ from connect24 import WebhookEvent, verify_signature
153
+
154
+ @app.post("/hooks/connect24")
155
+ def connect24_hook():
156
+ payload = request.get_data(as_text=True) # raw body, not request.json
157
+ signature = request.headers.get("X-Connect24-Signature", "")
158
+
159
+ if not verify_signature(payload, signature, WEBHOOK_SECRET):
160
+ return "", 401
161
+
162
+ event = WebhookEvent.parse(payload)
163
+ # Acknowledge fast — anything that is not 2xx is retried.
164
+ return "", 200
165
+ ```
166
+
167
+ Delivery is at-least-once. Deduplicate on `event.id`.
168
+
169
+ ## Errors
170
+
171
+ ```python
172
+ from connect24 import Connect24ApiError, Connect24ConnectionError
173
+
174
+ try:
175
+ client.messages.send_sms("+27821234567", "Hello")
176
+ except Connect24ApiError as e:
177
+ if e.status_code == 402:
178
+ ... # out of credit; topping up is the only fix
179
+ elif e.status_code == 401:
180
+ ... # key is wrong or revoked
181
+ print(e.errors) # field-level validation messages, when the API sent any
182
+ except Connect24ConnectionError:
183
+ ... # never reached the API — the send may or may not have happened
184
+ ```
185
+
186
+ Rate limits, 5xx and connection failures are retried twice with backoff before either is raised.
187
+ A 4xx is never retried, because repeating it changes nothing.
188
+
189
+ ## What the send path enforces
190
+
191
+ Messages sent through Connect24 are subject to South African law, applied where the message is
192
+ actually sent rather than left to you:
193
+
194
+ - **POPIA** — a lawful basis is recorded per contact, with where the details came from.
195
+ - **Consumer Protection Act** — no marketing on Sundays or public holidays, Saturdays 09:00–13:00
196
+ only, weekdays 08:00–20:00. A marketing send outside the window waits rather than going out late.
197
+ - **WASPA Code** — a working opt-out on every marketing message. Once used, it applies across every
198
+ list, permanently, and cannot be reversed by the sender.
199
+
200
+ Connect24 enforces these in the send path. You remain the responsible party under POPIA for the
201
+ data you upload and the consent you hold — see the [terms](https://connect24.co.za/terms).
202
+
203
+ ## Development
204
+
205
+ ```bash
206
+ pip install -e ".[dev]"
207
+ pytest
208
+ ```
209
+
210
+ ## Links
211
+
212
+ - [API documentation](https://connect24.co.za/developer)
213
+ - [Support](mailto:support@connect24.co.za)
@@ -0,0 +1,163 @@
1
+ # Connect24 Python SDK
2
+
3
+ Official Python client for the [Connect24](https://connect24.co.za) communications API —
4
+ one interface for email, SMS and WhatsApp.
5
+
6
+ ```bash
7
+ pip install connect24
8
+ ```
9
+
10
+ No runtime dependencies. An SDK is a dependency of *your* application, and every package it drags
11
+ in is a version conflict that becomes yours to resolve.
12
+
13
+ ## Quick start
14
+
15
+ Get your **account id** and an **API key** from the portal, under Settings → API keys.
16
+
17
+ ```python
18
+ import os
19
+ from connect24 import Connect24
20
+
21
+ client = Connect24(
22
+ account_id="acc_3f9c1a7b4e2d",
23
+ api_key=os.environ["CONNECT24_API_KEY"],
24
+ )
25
+
26
+ client.messages.send_sms("+27821234567", "Your payment is due tomorrow.")
27
+ ```
28
+
29
+ Or read both from the environment, which is what most deployments want:
30
+
31
+ ```python
32
+ client = Connect24.from_env() # CONNECT24_ACCOUNT_ID, CONNECT24_API_KEY
33
+ ```
34
+
35
+ ## What you can reach
36
+
37
+ | | |
38
+ |---|---|
39
+ | `client.messages` | Send email, SMS and WhatsApp; read status and history |
40
+ | `client.templates` | Stored bodies with placeholders, so copy lives on the platform |
41
+ | `client.suppressions` | Addresses that will not be sent to |
42
+ | `client.webhooks` | Delivery events pushed to you, plus signature verification |
43
+ | `client.sending_domains` | Prove you control a domain, so mail goes out as you |
44
+ | `client.billing` | Prepaid credit, pricing and the statement |
45
+ | `client.account` | Who you are, and which channels can send right now |
46
+
47
+ ## Every channel, one shape
48
+
49
+ ```python
50
+ # SMS
51
+ client.messages.send_sms("+27821234567", "Your delivery is on its way.")
52
+
53
+ # WhatsApp — free-form inside the 24-hour window, a template outside it
54
+ client.messages.send_whatsapp("+27821234567", "Your order has shipped.")
55
+ client.messages.send_whatsapp("+27821234567", template_name="payment_reminder")
56
+
57
+ # Email
58
+ client.messages.send_email(
59
+ to="customer@example.com",
60
+ subject="Payment reminder",
61
+ html="<p>Your account is overdue.</p>",
62
+ sender={"address": "collections@acme.co.za", "name": "Acme Collections"},
63
+ )
64
+ ```
65
+
66
+ ## Two things that surprise people
67
+
68
+ **Your `sender` address is not used until you verify the domain.** Until then mail leaves from your
69
+ account's assigned address on `connect24.co.za` and yours becomes the Reply-To. Verify with
70
+ `client.sending_domains.add("acme.co.za")`, publish the returned DNS records, then `verify`.
71
+
72
+ **There is no sender for SMS.** South African traffic routes from a shared originator pool, and
73
+ naming an identity you do not own is rejected by the network.
74
+
75
+ ## Not sending twice
76
+
77
+ Pass an idempotency key when a network failure leaves you unsure whether a send arrived. A repeat
78
+ with the same key returns the original message instead of sending again:
79
+
80
+ ```python
81
+ client.messages.send_sms(
82
+ "+27821234567",
83
+ "Your order has shipped.",
84
+ idempotency_key=f"order-{order.id}-shipped",
85
+ )
86
+ ```
87
+
88
+ Use something stable and tied to the event — an order id, not a UUID generated at call time, which
89
+ would differ on the retry and defeat the point.
90
+
91
+ ## Watch the emoji
92
+
93
+ An SMS holds 160 characters using the GSM-7 alphabet. A single emoji, curly quote or em dash
94
+ switches the whole message to UCS-2, which holds 70 characters per part. A 150-character message
95
+ with one emoji costs **three** SMS, not one. The portal shows the segment count while you write.
96
+
97
+ ## Verifying a webhook
98
+
99
+ Verify against the **raw body**, before any framework parses it.
100
+
101
+ ```python
102
+ from connect24 import WebhookEvent, verify_signature
103
+
104
+ @app.post("/hooks/connect24")
105
+ def connect24_hook():
106
+ payload = request.get_data(as_text=True) # raw body, not request.json
107
+ signature = request.headers.get("X-Connect24-Signature", "")
108
+
109
+ if not verify_signature(payload, signature, WEBHOOK_SECRET):
110
+ return "", 401
111
+
112
+ event = WebhookEvent.parse(payload)
113
+ # Acknowledge fast — anything that is not 2xx is retried.
114
+ return "", 200
115
+ ```
116
+
117
+ Delivery is at-least-once. Deduplicate on `event.id`.
118
+
119
+ ## Errors
120
+
121
+ ```python
122
+ from connect24 import Connect24ApiError, Connect24ConnectionError
123
+
124
+ try:
125
+ client.messages.send_sms("+27821234567", "Hello")
126
+ except Connect24ApiError as e:
127
+ if e.status_code == 402:
128
+ ... # out of credit; topping up is the only fix
129
+ elif e.status_code == 401:
130
+ ... # key is wrong or revoked
131
+ print(e.errors) # field-level validation messages, when the API sent any
132
+ except Connect24ConnectionError:
133
+ ... # never reached the API — the send may or may not have happened
134
+ ```
135
+
136
+ Rate limits, 5xx and connection failures are retried twice with backoff before either is raised.
137
+ A 4xx is never retried, because repeating it changes nothing.
138
+
139
+ ## What the send path enforces
140
+
141
+ Messages sent through Connect24 are subject to South African law, applied where the message is
142
+ actually sent rather than left to you:
143
+
144
+ - **POPIA** — a lawful basis is recorded per contact, with where the details came from.
145
+ - **Consumer Protection Act** — no marketing on Sundays or public holidays, Saturdays 09:00–13:00
146
+ only, weekdays 08:00–20:00. A marketing send outside the window waits rather than going out late.
147
+ - **WASPA Code** — a working opt-out on every marketing message. Once used, it applies across every
148
+ list, permanently, and cannot be reversed by the sender.
149
+
150
+ Connect24 enforces these in the send path. You remain the responsible party under POPIA for the
151
+ data you upload and the consent you hold — see the [terms](https://connect24.co.za/terms).
152
+
153
+ ## Development
154
+
155
+ ```bash
156
+ pip install -e ".[dev]"
157
+ pytest
158
+ ```
159
+
160
+ ## Links
161
+
162
+ - [API documentation](https://connect24.co.za/developer)
163
+ - [Support](mailto:support@connect24.co.za)
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "connect24"
7
+ version = "0.1.0"
8
+ description = "Official Python client for the Connect24 communications API — email, SMS and WhatsApp."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { file = "LICENSE" }
12
+ authors = [{ name = "Connect24" }]
13
+ keywords = [
14
+ "sms",
15
+ "email",
16
+ "whatsapp",
17
+ "messaging api",
18
+ "sms api",
19
+ "south africa",
20
+ "popia",
21
+ "connect24",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Intended Audience :: Developers",
26
+ "License :: OSI Approved :: MIT License",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.9",
29
+ "Programming Language :: Python :: 3.10",
30
+ "Programming Language :: Python :: 3.11",
31
+ "Programming Language :: Python :: 3.12",
32
+ "Programming Language :: Python :: 3.13",
33
+ "Topic :: Communications",
34
+ "Topic :: Software Development :: Libraries :: Python Modules",
35
+ "Typing :: Typed",
36
+ ]
37
+
38
+ # No runtime dependencies, on purpose. An SDK is a dependency of somebody else's application, and
39
+ # every package it drags in is a version conflict that becomes theirs to resolve. JSON over HTTPS
40
+ # is something the standard library does perfectly well.
41
+ dependencies = []
42
+
43
+ [project.urls]
44
+ Homepage = "https://connect24.co.za"
45
+ Documentation = "https://connect24.co.za/developer"
46
+ Source = "https://github.com/Lihle2018/connect24-python"
47
+
48
+ [project.optional-dependencies]
49
+ dev = ["pytest>=7", "mypy>=1.8", "ruff>=0.4"]
50
+
51
+ [tool.hatch.build.targets.wheel]
52
+ packages = ["src/connect24"]
53
+
54
+ [tool.pytest.ini_options]
55
+ testpaths = ["tests"]
56
+ pythonpath = ["src"]
57
+
58
+ [tool.ruff]
59
+ line-length = 100
60
+ src = ["src", "tests"]
61
+
62
+ [tool.ruff.lint]
63
+ select = ["E", "F", "I", "UP", "B"]
64
+
65
+ [tool.mypy]
66
+ python_version = "3.9"
67
+ files = ["src/connect24"]
68
+ strict = true
@@ -0,0 +1,61 @@
1
+ """Official Python client for the Connect24 communications API.
2
+
3
+ One interface for email, SMS and WhatsApp::
4
+
5
+ from connect24 import Connect24
6
+
7
+ client = Connect24.from_env()
8
+ client.messages.send_sms("+27821234567", "Your order has shipped.")
9
+
10
+ Two things surprise people, both of them deliberate:
11
+
12
+ **Your ``from`` address is not used until you verify the domain.** Until then mail leaves from your
13
+ account's assigned address on ``connect24.co.za`` and yours becomes the Reply-To.
14
+
15
+ **There is no sender for SMS.** South African traffic routes from a shared originator pool, and
16
+ naming an identity you do not own is rejected by the network.
17
+ """
18
+
19
+ from .client import DEFAULT_BASE_URL, Connect24
20
+ from .errors import Connect24ApiError, Connect24ConnectionError, Connect24Error
21
+ from .models import (
22
+ AccountInfo,
23
+ Balance,
24
+ ChannelStatus,
25
+ LedgerEntry,
26
+ Message,
27
+ MessageAccepted,
28
+ SendingDomain,
29
+ Suppression,
30
+ Template,
31
+ WebhookDelivery,
32
+ WebhookEndpoint,
33
+ WebhookEvent,
34
+ )
35
+ from .webhooks import DEFAULT_TOLERANCE_SECONDS, timestamp_of, verify_signature
36
+
37
+ __version__ = "0.1.0"
38
+
39
+ __all__ = [
40
+ "Connect24",
41
+ "DEFAULT_BASE_URL",
42
+ "Connect24Error",
43
+ "Connect24ApiError",
44
+ "Connect24ConnectionError",
45
+ "verify_signature",
46
+ "timestamp_of",
47
+ "DEFAULT_TOLERANCE_SECONDS",
48
+ "WebhookEvent",
49
+ "AccountInfo",
50
+ "Balance",
51
+ "ChannelStatus",
52
+ "LedgerEntry",
53
+ "Message",
54
+ "MessageAccepted",
55
+ "SendingDomain",
56
+ "Suppression",
57
+ "Template",
58
+ "WebhookDelivery",
59
+ "WebhookEndpoint",
60
+ "__version__",
61
+ ]