Connect24 Python SDK
Official Python client for the Connect24 communications API — one interface for email, SMS and WhatsApp.
pip install connect24
No runtime dependencies. An SDK is a dependency of your application, and every package it drags in is a version conflict that becomes yours to resolve.
Quick start
Get your account id and an API key from the portal, under Settings → API keys.
import os
from connect24 import Connect24
client = Connect24(
account_id="acc_3f9c1a7b4e2d",
api_key=os.environ["CONNECT24_API_KEY"],
)
client.messages.send_sms("+27821234567", "Your payment is due tomorrow.")
Or read both from the environment, which is what most deployments want:
client = Connect24.from_env() # CONNECT24_ACCOUNT_ID, CONNECT24_API_KEY
What you can reach
client.messages |
Send email, SMS and WhatsApp; read status and history |
client.templates |
Stored bodies with placeholders, so copy lives on the platform |
client.suppressions |
Addresses that will not be sent to |
client.webhooks |
Delivery events pushed to you, plus signature verification |
client.sending_domains |
Prove you control a domain, so mail goes out as you |
client.billing |
Prepaid credit, pricing and the statement |
client.account |
Who you are, and which channels can send right now |
Every channel, one shape
# SMS
client.messages.send_sms("+27821234567", "Your delivery is on its way.")
# WhatsApp — free-form inside the 24-hour window, a template outside it
client.messages.send_whatsapp("+27821234567", "Your order has shipped.")
client.messages.send_whatsapp("+27821234567", template_name="payment_reminder")
# Email
client.messages.send_email(
to="customer@example.com",
subject="Payment reminder",
html="<p>Your account is overdue.</p>",
sender={"address": "collections@acme.co.za", "name": "Acme Collections"},
)
Two things that surprise people
Your sender address is not used until you verify the domain. Until then mail leaves from your
account's assigned address on connect24.co.za and yours becomes the Reply-To. Verify with
client.sending_domains.add("acme.co.za"), publish the returned DNS records, then verify.
There is no sender for SMS. South African traffic routes from a shared originator pool, and naming an identity you do not own is rejected by the network.
Not sending twice
Pass an idempotency key when a network failure leaves you unsure whether a send arrived. A repeat with the same key returns the original message instead of sending again:
client.messages.send_sms(
"+27821234567",
"Your order has shipped.",
idempotency_key=f"order-{order.id}-shipped",
)
Use something stable and tied to the event — an order id, not a UUID generated at call time, which would differ on the retry and defeat the point.
Watch the emoji
An SMS holds 160 characters using the GSM-7 alphabet. A single emoji, curly quote or em dash switches the whole message to UCS-2, which holds 70 characters per part. A 150-character message with one emoji costs three SMS, not one. The portal shows the segment count while you write.
Verifying a webhook
Verify against the raw body, before any framework parses it.
from connect24 import WebhookEvent, verify_signature
@app.post("/hooks/connect24")
def connect24_hook():
payload = request.get_data(as_text=True) # raw body, not request.json
signature = request.headers.get("X-Connect24-Signature", "")
if not verify_signature(payload, signature, WEBHOOK_SECRET):
return "", 401
event = WebhookEvent.parse(payload)
# Acknowledge fast — anything that is not 2xx is retried.
return "", 200
Delivery is at-least-once. Deduplicate on event.id.
Errors
from connect24 import Connect24ApiError, Connect24ConnectionError
try:
client.messages.send_sms("+27821234567", "Hello")
except Connect24ApiError as e:
if e.status_code == 402:
... # out of credit; topping up is the only fix
elif e.status_code == 401:
... # key is wrong or revoked
print(e.errors) # field-level validation messages, when the API sent any
except Connect24ConnectionError:
... # never reached the API — the send may or may not have happened
Rate limits, 5xx and connection failures are retried twice with backoff before either is raised. A 4xx is never retried, because repeating it changes nothing.
What the send path enforces
Messages sent through Connect24 are subject to South African law, applied where the message is actually sent rather than left to you:
- POPIA — a lawful basis is recorded per contact, with where the details came from.
- Consumer Protection Act — no marketing on Sundays or public holidays, Saturdays 09:00–13:00 only, weekdays 08:00–20:00. A marketing send outside the window waits rather than going out late.
- WASPA Code — a working opt-out on every marketing message. Once used, it applies across every list, permanently, and cannot be reversed by the sender.
Connect24 enforces these in the send path. You remain the responsible party under POPIA for the data you upload and the consent you hold — see the terms.
Development
pip install -e ".[dev]"
pytest
Links
Metadata
Release files for connect24 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| connect24-0.2.0.tar.gz | 20.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| connect24-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.3 kB
Release files / connect24-0.2.0.tar.gz
| Download URL | connect24-0.2.0.tar.gz |
|---|---|
| Size | 20.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1808846bbfc3f2c583c39175cfd64813ec2c54e2518301c9324c444fd121e72d
|
|
BLAKE2b-256 checksum How to use checksums |
74e65f64aa47dfcc547e3e8e5f56e5ee2efd5292e794f653d61547fff2db5a46
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.
Transparency logRelease files / connect24-0.2.0-py3-none-any.whl
| Download URL | connect24-0.2.0-py3-none-any.whl |
|---|---|
| Size | 24.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
aecb48c9eec7981890ed87513d21c9a4f29d25d3c82d2c48108c0eb4ab54798f
|
|
BLAKE2b-256 checksum How to use checksums |
13c7fd7651e872c5bcef93c3ce077ed098a7643d1da838800df1050b97804e84
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 30, 2026.
Transparency log