A simple FastAPI project with Twilio SMS webhook support.
- POST /message: Twilio SMS webhook handler - receives SMS messages and returns "hello world" (TwiML)
- GET /health: Health check endpoint
Make sure you have uv installed. If not, install it:
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or using pip
pip install uv-
Clone/Navigate to the project directory:
cd pigeon -
Create a virtual environment and install dependencies:
uv venv source .venv/bin/activate # On Windows: .venv\Scripts\activate uv pip install -r requirements.txt
Alternatively, you can install dependencies directly:
uv pip install fastapi uvicorn[standard] pydantic python-multipart
Start the FastAPI server using uvicorn:
uvicorn main:app --reload --host 0.0.0.0 --port 8000The server will start and be available at:
- API Base URL: http://localhost:8000
- Interactive Docs: http://localhost:8000/docs
- Alternative Docs: http://localhost:8000/redoc
-
Get your server URL:
- For local development, use ngrok:
ngrok http 8000 - For production, use your domain:
https://yourdomain.com
- For local development, use ngrok:
-
Configure Twilio Console:
- Go to Twilio Console
- Navigate to Phone Numbers → Manage → Active numbers
- Click on your Twilio phone number
- Set the SMS webhook URL:
https://your-domain.com/message
-
Test with ngrok (for local development):
# In one terminal uvicorn main:app --reload # In another terminal ngrok http 8000
Use the ngrok HTTPS URL for your webhook configuration:
https://abc123.ngrok.io/message
When someone sends an SMS to your Twilio number:
- Twilio receives the SMS
- Twilio sends a POST request to your
/messageendpoint with form data:From=+1234567890 To=+0987654321 Body=Hello there! MessageSid=SM123abc456def AccountSid=AC123... - Your API responds with TwiML to send "hello world" back:
<?xml version="1.0" encoding="UTF-8"?> <Response> <Message>hello world</Message> </Response>
- Twilio sends the "hello world" message back to the original sender
curl -X GET "http://localhost:8000/health"Expected response:
{"status": "ok"}curl -X POST "http://localhost:8000/message" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "From=%2B1234567890&To=%2B0987654321&Body=Test%20message&MessageSid=SM123abc456def"Expected response (TwiML):
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>hello world</Message>
</Response>- Open your browser and go to http://localhost:8000/docs
- You'll see the Swagger UI with both endpoints
- Click on any endpoint to expand it
- Click "Try it out" to test the endpoints
| Method | Endpoint | Description | Request Format | Response Format |
|---|---|---|---|---|
| GET | /health |
Health check | None | JSON |
| POST | /message |
Twilio SMS webhook | Form data | TwiML (XML) |
To run in development mode with auto-reload:
uvicorn main:app --reloadThis will automatically restart the server when you make changes to the code.
- Use HTTPS in production for Twilio webhooks
- The
/messageendpoint logs incoming messages to console - customize this for your needs - Consider implementing Twilio request validation for security in production