notavia
Official Python SDK for Notavia — send transactional email and manage templates.
Features: ✓ Notifications API ✓ Templates API ✓ Inbox API ✓ Preferences API ✓ Webhooks ✓ SMS ✓ Chat channels (Slack / Teams / Discord) ✓ Workflows API
Install
pip install notavia
Send your first notification
from notifyservice import NotifyClient
from notifyservice_api.models.send_notification_request import SendNotificationRequest
from notifyservice_api.models.recipient import Recipient
client = NotifyClient(
base_url="https://api.notavia.saas-infrastructure.com",
api_key="ns_live_...",
)
notification = client.notifications.send_notification(
SendNotificationRequest(
channel="email",
recipient=Recipient(address="alice@example.com", name="Alice"),
subject="Welcome",
html_body="<h1>Hello!</h1>",
)
)
print(notification.id)
Idempotency
Pass idempotency_key to guarantee at-most-once delivery. Repeat requests with the same key within 24 hours return the original response without re-sending:
notification = client.notifications.send_notification(request, idempotency_key=f"signup-{user_id}")
Templates
Create a stored template, then reference it by key at send time:
from notifyservice_api.models.create_template_request import CreateTemplateRequest
from notifyservice_api.models.render_template_request import RenderTemplateRequest
client.templates.create_template(
CreateTemplateRequest(
key="welcome",
name="Welcome email",
subject_template="Welcome, {{name}}!",
html_body_template="<h1>Hello, {{name}}.</h1>",
)
)
# Preview a template with data before sending
rendered = client.templates.render_template(
"welcome",
RenderTemplateRequest(data={"name": "Alice"}),
)
print(rendered.subject) # "Welcome, Alice!"
print(rendered.html_body) # "<h1>Hello, Alice.</h1>"
# Send using the stored template
client.notifications.send_notification(
SendNotificationRequest(
channel="email",
recipient=Recipient(address="alice@example.com"),
template_key="welcome",
template_data={"name": "Alice"},
)
)
SMS
client.notifications.send_notification(
SendNotificationRequest(
channel="sms",
recipient=Recipient(external_user_id="usr_1"),
template_key="order_shipped_sms",
template_data={"order_id": "ord_99"},
)
)
Chat channels
Slack (DM by user id)
client.notifications.send_notification(
SendNotificationRequest(
channel="slack",
recipient=Recipient(external_user_id="usr_1", slack_user_id="U07XYZ123"),
template_key="invoice_paid_slack",
template_data={"invoice_id": "inv_42"},
)
)
To post to a Slack channel instead of a user DM, use slack_channel_id:
recipient=Recipient(external_user_id="usr_1", slack_channel_id="C07XYZ123")
Microsoft Teams
Teams requires an endpoint registered first via POST /v1/teams-endpoints. Use the returned UUID:
client.notifications.send_notification(
SendNotificationRequest(
channel="teams",
recipient=Recipient(external_user_id="team_alerts", teams_endpoint_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
template_key="incident_alert_teams",
)
)
Discord
Discord requires an endpoint registered first via POST /v1/discord-endpoints. Use the returned UUID:
client.notifications.send_notification(
SendNotificationRequest(
channel="discord",
recipient=Recipient(external_user_id="team_alerts", discord_endpoint_id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"),
template_key="incident_alert_discord",
)
)
Webhook signature verification
Verify incoming webhook payloads using your signing secret (prefixed whsec_):
from notifyservice import verify_signature
is_valid = verify_signature(
raw_body=request.body,
signature_header=request.headers["NotifyService-Signature"],
signing_secret="whsec_...",
)
if not is_valid:
raise ValueError("Invalid webhook signature")
Delegated tokens (inbox & preferences)
Mint short-lived JWTs so your frontend can access the inbox or preferences widgets directly without exposing your API key:
from notifyservice import mint_inbox_token, mint_prefs_token, mint_inbox_and_prefs_token
# Inbox only
token = mint_inbox_token(
organization_id="org_123",
external_user_id="usr_456",
signing_key="nsi_...", # must start with nsi_
ttl_seconds=900, # default 15 min, min 60, max 86400
)
# Preferences only
token = mint_prefs_token("org_123", "usr_456", "nsi_...")
# Both scopes in one token
token = mint_inbox_and_prefs_token("org_123", "usr_456", "nsi_...")
Decode a token to inspect its claims:
from notifyservice import decode
payload = decode(token)
print(payload.iss, payload.sub, payload.scope, payload.exp)
Error handling
The generated API layer raises notifyservice_api.exceptions.ApiException on non-2xx responses. The .status attribute holds the HTTP status code and .body holds the raw response body (a JSON string with code, message, and param fields):
import json
from notifyservice_api.exceptions import ApiException
try:
client.notifications.send_notification(request)
except ApiException as exc:
if exc.status == 400:
error = json.loads(exc.body)
print(f"{error['code']}: {error['message']} (param: {error.get('param')})")
elif exc.status == 429:
# rate-limited — the SDK already retried up to 3 times
raise
else:
raise
Retries
The SDK retries up to 3 times on transient failures (429, 502, 503, 504) with exponential backoff and Retry-After support. Adjust at construction time:
client = NotifyClient(base_url="...", api_key="...", max_retries=5)
Disable retries entirely:
client = NotifyClient(base_url="...", api_key="...", max_retries=0)
Compatibility
- Python 3.9+
- Dependencies:
pydantic,urllib3
License
MIT.
Release files for notavia 1.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| notavia-1.0.2.tar.gz | 97.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| notavia-1.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 426.6 kB
Release files / notavia-1.0.2.tar.gz
| Download URL | notavia-1.0.2.tar.gz |
|---|---|
| Size | 97.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
73182ef08a6e24cdf2dc70933e583c94d384f820cd1146d748910537beb85483
|
|
BLAKE2b-256 checksum How to use checksums |
45d6f52eb7e498f18602c2319b75c805ab494fb97d7b59c14480c11780ffa2c4
|
| 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 15, 2026.
Transparency logRelease files / notavia-1.0.2-py3-none-any.whl
| Download URL | notavia-1.0.2-py3-none-any.whl |
|---|---|
| Size | 329.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
61c3c2095d836d6309b957028a7426369f808f29a49293e8556885dcd4a4ffd2
|
|
BLAKE2b-256 checksum How to use checksums |
468693347a25052930f6d4210f09449fc03a0fda5c5b2bd9fb06cf9fb56ca395
|
| 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 15, 2026.
Transparency log