Skip to content

The nexafon package needs Python 3.9 or later and has no dependencies.

Terminal window
pip install nexafon
app.py
def may_use_nexafon(user):
# Everyone who gets a token may reach your workspace's inbox and calls: answer 403 unless the user is your staff,
# never a customer who signed up. The sample's user is the teammate you invited.
return user["is_staff"]
def nexafon_token(user):
# Signed with NEXAFON_SECRET_KEY (sk_test_… or sk_live_…), which never leaves this server.
# Nexafon links a first sign-in to the member with this email only when it is verified: never send True for
# an address your app has not confirmed, or whoever sets a member's email on your app acts as that member.
return nexafon.create_user_token(
user["id"], user["name"], "agent", email=user["email"], email_verified=user["email_verified"]
)

Keyword options: secret_key (defaults to NEXAFON_SECRET_KEY) and expires_in (seconds, at most 600). Invalid input raises nexafon.NexafonTokenError.

app.py
if self.path == "/hooks/nexafon":
# The raw body, exactly as received: parsing it first changes the bytes the signature covers.
raw = self.rfile.read(int(self.headers.get("Content-Length", 0)))
try:
event = nexafon.verify_webhook(dict(self.headers), raw, os.environ["NEXAFON_WEBHOOK_SECRET"])
except nexafon.WebhookVerificationError:
self.send_response(400)
self.end_headers()
return
# Deliveries can repeat: skip an event["id"] you have already handled.
print(event["type"], event["id"])
self.send_response(204)
self.end_headers()
return

With Flask pass request.headers and request.get_data(); with Django request.headers and request.body.

The sample is a complete standard-library server (python3 app.py).