Bird

Send SMS with Django

Send a booking reminder from a server route, keep the accepted message ID and read its delivery status. This example uses the existing Bird Python SDK.

1. Prepare the workspace

Prepare an SMS-capable US number owned by your workspace, enable the US destination, complete its required sender registration and add balance. The fixed recipient +15005550006 simulates delivery, is billed at the normal destination rate and does not reach a handset. Complete the first-message setup and create a server-side API key before running the application.

2. Create the application

Use Python 3.10 or later. This example uses a local HTML form and keeps Django's CSRF protection enabled.
Ejemplo de código
mkdir bird-sms-django
cd bird-sms-django
python3 -m venv .venv
source .venv/bin/activate
python -m pip install messagebird-sdk "django>=5.2,<6"
django-admin startproject config .
python manage.py startapp reminders
export BIRD_API_KEY="YOUR_API_KEY"
export BIRD_SMS_FROM="YOUR_ELIGIBLE_US_NUMBER"

3. Add the view and form

Save this as reminders/views.py. A GET shows a CSRF-protected form. A POST sends the fixed reminder with the form's operation ID. Reading a status uses GET and does not send another message.
Ejemplo de código
import logging
import os
from uuid import UUID, uuid4

from bird import Bird, APIError
from django.http import JsonResponse, HttpResponse
from django.middleware.csrf import get_token
from django.utils.html import format_html
from django.views.decorators.http import require_http_methods


@require_http_methods(["GET", "POST"])
def messages(request):
    if request.method == "GET" and not request.GET.get("id"):
        return HttpResponse(format_html(
            '<form method="post"><input type="hidden" name="csrfmiddlewaretoken" value="{}">'
            '<input type="hidden" name="operation_id" value="{}">'
            '<button type="submit">Send test reminder</button></form>',
            get_token(request), str(uuid4()),
        ))
    if request.method == "POST":
        operation_id = request.POST.get("operation_id", "")
        try:
            UUID(operation_id)
        except ValueError:
            return JsonResponse({"error": "Invalid operation ID."}, status=400)
    try:
        with Bird(api_key=os.environ["BIRD_API_KEY"]) as client:
            if request.method == "GET":
                message = client.sms.get(request.GET["id"])
            else:
                message = client.sms.send(
                    from_=os.environ["BIRD_SMS_FROM"],
                    to="+15005550006",
                    text="Your studio visit is tomorrow at 14:00.",
                    category="transactional",
                    metadata={"booking": "FN-1042"},
                    options={"idempotency_key": operation_id},
                )
            return JsonResponse(
                {"id": message.id, "status": message.status},
                status=202 if request.method == "POST" else 200,
            )
    except APIError:
        logging.exception("Bird SMS request failed")
        return JsonResponse({"error": "Could not confirm the result. Inspect the original attempt before retrying."}, status=503)
Replace config/urls.py with:
Ejemplo de código
from django.urls import path
from reminders.views import messages

urlpatterns = [path("api/sms/messages", messages)]

4. Run the example

Ejemplo de código
python manage.py runserver 127.0.0.1:8000
Open http://127.0.0.1:8000/api/sms/messages and submit the form once. It returns the accepted message ID. The hidden operation ID belongs to that form submission; loading a fresh form creates a new operation. A form ID is sample request identity, not customer authentication. Follow the Django deployment checklist before deploying an application.

Inspect the result and recover

The POST returns 202 with the message id and current status. Acceptance precedes delivery. Copy the ID and read it without sending again:
Ejemplo de código
curl "http://127.0.0.1:8000/api/sms/messages?id=YOUR_MESSAGE_ID"
The read returns the recorded status. Follow SMS events for asynchronous outcomes, and use the product log or event guide to investigate a missing receipt. A missing receipt does not establish delivery or failure.
  • An invalid operation_id produces 400; a missing or invalid CSRF token produces 403 in this application before it calls Bird.
  • If the send fails, the application returns 503 and leaves the result unresolved. Inspect the SDK error in the server terminal and the product log. Correct authentication, sender, destination, template or balance errors before retrying.
  • For an uncertain response, retain the same key and identical payload. Read the idempotency guide before retrying; a new key creates a new operation, and response retention does not provide an indefinite exactly-once guarantee.
For real reminders, load the booking and its permitted recipient from your database after authorizing the caller. Keep the booking ID with the accepted message ID. Handle replies and opt-outs before adding an automated reply.
These handlers use a fixed test recipient and bind the development server to loopback. Before publishing, authorize each customer action, associate message IDs with the owning account before permitting reads, and apply your application's abuse limits. The booking and workflow are sample application logic.

Continue the integration