
Share:
Benjamin Aronov is a developer advocate at Vonage. He is a proven community builder with a background in Ruby on Rails. Benjamin enjoys the beaches of Tel Aviv which he calls home. His Tel Aviv base allows him to meet and learn from some of the world's best startup founders. Outside of tech, Benjamin loves traveling the world in search of the perfect pain au chocolat.
Sandbox Quickstart: Send and Receive WhatsApp Messages With Python
Introduction
Want to send and receive WhatsApp messages using Python super fast? Whether you're testing a chatbot, building a messaging prototype, or just exploring the Vonage Messages API, the Vonage WhatsApp Sandbox lets you get started in a few minutes.
In this tutorial, we’ll walk through how to send and receive WhatsApp messages in Python using Flask, a lightweight web framework ideal for quick API experiments. You won’t need to set up a full Vonage application or worry about a WhatsApp Business Account (WABA). This is the fastest way to try out the Vonage Messages API with WhatsApp in Python!
Prerequisites
You’ll need the following tools and accounts to follow along:
Vonage API Account
Vonage API Account
To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.
Set Up the WhatsApp Sandbox
Log in to the Vonage API Dashboard.
Navigate to Messaging > Messages Sandbox.
Scan the QR code with WhatsApp to join the sandbox.
Add your phone number to the allowlist by sending the pre-filled message.
You’ll get a reply letting you know that your number has been allowlisted, something like “Thank you! Your number is now set up on the skid froze Messages API Sandbox.”
Keep your sandbox number handy (usually something like 14157386102).
Next, you’ll need to set up the webhooks for the sandbox to connect to our Flask app. For this, we have ngrok. So open your command-line terminal and run:
ngrok http 3000You now have your ngrok URL that looks something like:
Forwarding
https://59bd32ee0a4e.ngrok-free.app -> http://localhost:3000 So now you can update the webhooks:
For Inbound:
https://YOUR_NGROK_URL/inboundFor Status:
https://YOUR_NGROK_URL/status
And then click on the ‘Save webhooks’ button. For more help, see Testing with ngrok.
Example of configured webhooks for inbound messages and status updates using ngrok URLs
Initialize Your Python Flask Project
Now, open a new tab in your terminal, while continuing to let your ngrok tunnel run. In the second tab, you can paste the following commands to create your project:
mkdir quickstart-whatsapp-python
cd quickstart-whatsapp-python
python3 -m venv venv
source venv/bin/activate
touch app.py config.py .env Install Required Dependencies
Flask: A lightweight Python web framework used to create your WhatsApp webhook server with minimal setup.
Python-dotenv: Loads environment variables from your .env file into os.environ, keeping sensitive info like API keys out of your source code.
pip install python-dotenv flask
pip install requests
pip freeze > requirements.txt Add Your Environment Variables
Inside .env you’ll need to add your Sandbox phone number from the previous step, as well as your API_KEY and API_SECRET which can be found in your API Settings page.
VONAGE_API_KEY=your-vonage-api-key
VONAGE_API_SECRET=your-vonage-api-secret
VONAGE_SANDBOX_NUMBER=your-vonage-sandbox-number
PORT=3000See our Python Environment Variables guide for more information
Configure Your Environment
Before we start sending messages, we need to load our environment variables and prepare the authentication header for the Vonage Messages API.
In your config.py file, add the following:
import os
import base64
from dotenv import load_dotenv
load_dotenv()
VONAGE_API_KEY = os.getenv("VONAGE_API_KEY")
VONAGE_API_SECRET = os.getenv("VONAGE_API_SECRET")
VONAGE_SANDBOX_NUMBER = os.getenv("VONAGE_SANDBOX_NUMBER")
VONAGE_URL = "https://messages-sandbox.nexmo.com/v1/messages"
# Create Base64 encoded auth header
credentials = f"{VONAGE_API_KEY}:{VONAGE_API_SECRET}"
encoded_credentials = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
VONAGE_AUTH_HEADER = f"Basic {encoded_credentials}"
Implement Your WhatsApp Logic
Now that your project is wired up with credentials, it’s time to bring your Flask app to life. In this file, you’ll define the core logic for sending and receiving WhatsApp messages using the Vonage Sandbox.
You’ll start by setting up two endpoints: one to handle incoming messages (/inbound) and one for message status updates (/status). When someone sends a WhatsApp message to your sandbox number, Vonage forwards it to your Flask server. Your app will log the message content to the terminal, as a bit of fun, it will reverse the text, and send it back as a reply. This gives your app a full loop from WhatsApp → Flask → WhatsApp.
Add the following to your app.py file to receive webhooks and send messages:
import os
import json
import logging
import requests
from flask import Flask, request, Response
from config import *
app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
def send_whatsapp_reply(to, message_text):
payload = {
"from": VONAGE_SANDBOX_NUMBER,
"to": to,
"channel": "whatsapp",
"message_type": "text",
"text": message_text,
}
headers = {
"Content-Type": "application/json",
"Authorization": VONAGE_AUTH_HEADER,
}
response = requests.post(VONAGE_URL, headers=headers, data=json.dumps(payload))
response.raise_for_status()
@app.route("/inbound", methods=["POST"])
def inbound():
data = request.get_json()
sender = data.get("from")
text = data.get("text", "").strip()
logging.info(f"\n📩 Received message from {sender}:\n{text}\n")
if sender and text:
reversed_text = text[::-1]
reply = f"Thank you for your message! Here's what it looks like in reverse:\n\n{reversed_text}"
try:
send_whatsapp_reply(sender, reply)
except Exception as e:
logging.error(f"Failed to send message: {e}", exc_info=True)
return Response("Failed to send message", status=500)
return Response(status=200)
@app.route("/status", methods=["POST"])
def status():
data = request.get_json()
logging.info(f"📬 Status webhook received:\n{json.dumps(data, indent=2)}\n")
return Response(status=200)
if __name__ == "__main__":
port = int(os.getenv("PORT", 3000))
app.run(port=port) Test Your App
Start your Flask server in your non-ngrok terminal tab:
export FLASK_ENV=development
python3 app.pyOnce setup is complete:
Send a message from your allowlisted WhatsApp number to the sandbox number.
Your Flask app will receive the webhook and display it in the terminal.
It sends back a WhatsApp message to your number.
You should see a response like the one below. Can you guess what the original message was?
Example WhatsApp message showing reversed text output
Note: The Vonage Messages Sandbox is for development only. To move to production, you’ll need to create a Vonage Application and use a verified WhatsApp Business Account (WABA).
Conclusion
You've just built a real-time WhatsApp message handler in Python using Flask; no WABA, no JWTs, just instant two-way messaging with the Vonage Sandbox. This setup is great for validating webhook flows or quickly trying out some message logic. But what if you want to take it further?
Check out our post onconnecting WhatsApp to ChatGPT using Python. You’ll learn how to add OpenAI-powered responses to your Flask app and create a simple conversational assistant in just a few extra lines of code.
WhatsApp is powerful, but have you heard of RCS messaging? If your users are on Android, RCS lets you send rich content like carousels, buttons, and branded image messages. OurPython RCS guide shows you how to get started.
Have a question or something to share? Join the conversation on the Vonage Community Slack, stay up to date with the Developer Newsletter, follow us on X (formerly Twitter), subscribe to our YouTube channel for video tutorials, and follow the Vonage Developer page on LinkedIn, a space for developers to learn and connect with the community. Stay connected, share your progress, and keep up with the latest developer news, tips, and events!
Share:
Benjamin Aronov is a developer advocate at Vonage. He is a proven community builder with a background in Ruby on Rails. Benjamin enjoys the beaches of Tel Aviv which he calls home. His Tel Aviv base allows him to meet and learn from some of the world's best startup founders. Outside of tech, Benjamin loves traveling the world in search of the perfect pain au chocolat.
