Skip to content

Webhooks

1sms.az can call your server when a message changes state. Each call is signed, so you can confirm it really came from 1sms.az before acting on it.

How the signature works

Every webhook arrives with two headers:

  • X-1sms-Signature, an HMAC-SHA256 of the request, as hex.
  • X-1sms-Timestamp, the unix time the request was signed.

The signature is computed over the timestamp and the raw request body, keyed with your API secret. verify_signature recreates it and compares the two in constant time. It also rejects a timestamp more than five minutes old, so an old call cannot be replayed.

Verify a call

Always verify against the raw request body, before any JSON parsing reformats it.

from onesms import WebhookEvent, verify_signature

signature = request.headers["X-1sms-Signature"]
timestamp = request.headers["X-1sms-Timestamp"]
raw_body = request.get_data()

if not verify_signature("your_api_secret", timestamp, raw_body, signature):
    raise ValueError("Invalid webhook signature")

event = WebhookEvent.from_payload(request.get_json())
if event.is_final:
    print(event.message_id, event.status_text)

WebhookEvent reads the delivery fields out of the payload and gives you the same status and is_final helpers used elsewhere in the library.

Adjust the time window

The default tolerance is five minutes. Widen it with tolerance_seconds if your server clock drifts or you process calls from a queue:

verify_signature(secret, timestamp, raw_body, signature, tolerance_seconds=900)

Flask example

from flask import Flask, request

from onesms import WebhookEvent, verify_signature

app = Flask(__name__)
SECRET = "your_api_secret"


@app.post("/webhooks/1sms")
def receive():
    signature = request.headers.get("X-1sms-Signature", "")
    timestamp = request.headers.get("X-1sms-Timestamp", "")

    if not verify_signature(SECRET, timestamp, request.get_data(), signature):
        return "", 400

    event = WebhookEvent.from_payload(request.get_json())
    print(event.message_id, event.status_text)
    return "", 204