Skip to content

DevEngageLab/engagelab-otp-python

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

engagelab-otp · Python

Official Python SDK for EngageLab OTP.
Zero dependencies. Python 3.8+.

Install

pip install engagelab-otp

Quick start

import os
from engagelab_otp import OTPClient

otp = OTPClient(
    os.environ["ENGAGELAB_DEV_KEY"],
    os.environ["ENGAGELAB_DEV_SECRET"],
)

# Platform-generated OTP — easiest path
result = otp.send("+6591234567", "your-template-id", {"name": "Alice"}, language="en")
check  = otp.verify(result["message_id"], user_typed_code)
if check["verified"]:
    ...

Two send modes

Mode Method When to use
Platform-generated otp.send() EngageLab generates and stores the code. You only call verify() later.
Caller-generated otp.send_custom() You generate the code yourself. EngageLab is just the carrier.
# Platform-generated
r = otp.send("+6591234567", "tpl-id", {"name": "Alice"}, language="en")
v = otp.verify(r["message_id"], "123456")

# Caller-generated
otp.send_custom("+6591234567", "custom-tpl", {"code": "482910", "name": "Alice"})

Webhook callbacks

EngageLab signs callbacks with X-CALLBACK-ID (HMAC-SHA256). The SDK verifies signatures and parses events for you.

Whitelist source IPs in your firewall: 119.8.170.74, 114.119.180.30

from flask import Flask
from engagelab_otp import WebhookVerifier, MessageStatusEvent

app = Flask(__name__)

verifier = WebhookVerifier(
    username=os.environ["ENGAGELAB_WEBHOOK_USERNAME"],
    secret=os.environ["ENGAGELAB_WEBHOOK_SECRET"],
)

def handle(events):
    for e in events:
        if not isinstance(e, MessageStatusEvent):
            continue
        if not e.is_terminal:
            continue   # mid-flight, wait
        if e.status == "delivered":
            mark_delivered(e.message_id)
        elif e.status == "verified":
            mark_verified(e.message_id)

app.add_url_rule(
    "/webhook",
    "engagelab_webhook",
    verifier.flask_view(handle),
    methods=["POST"],
)

Event types

parse_events() returns instances of four dataclasses:

Class When Key fields
MessageStatusEvent per-message lifecycle message_id, status, is_terminal, current_send_channel, error_code
NotificationEvent account-level alert event, data
UplinkEvent inbound user reply data["from"], data["body"]
SystemEvent console action audit event, data

Message status enum

plan · target_valid · target_invalid
sent · sent_failed
delivered · delivered_failed
verified · verified_failed · verified_timeout

is_terminal == True for: delivered, delivered_failed, sent_failed, verified*, target_invalid.

Error handling

from engagelab_otp import EngagelabError

try:
    otp.send("+6591234567", "tpl", {})
except EngagelabError as e:
    if e.retryable:
        # HTTP 429/5xx, or API codes 1000/5001/5016
        # → exponential backoff
        ...
    else:
        # Permanent failure — fix call or notify user
        print(e.code, e.http_status, str(e))

Examples

See examples/ for runnable code:

  • 01_send_and_verify.py — platform-generated OTP, full flow
  • 02_send_custom.py — caller-generated code, single + bulk
  • 03_webhook_flask.py — receive callbacks via Flask
  • 04_error_handling.py — retry strategy and error categorization

Run tests

python tests/test_sdk.py

License

MIT

About

engagelab otp python sdk

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages