A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.
- Documentation: Full documentation site
- Node.js / TypeScript version: whatsapp-cloud-bot-ts
- GitHub: Repository
- PyPI: Package
- WhatsApp API Docs: Official documentation
- 🔄 Sync & Async Support: Mirror async versions of all functions (e.g.,
send_messageandasend_message) - 📝 Full Type Annotations: Python 3.6+ compatible type hints throughout the codebase
- 💬 Text Messages: Send and receive text messages with preview support
- 🎯 Interactive Messages: Buttons, lists, and location requests
- 📄 Template Messages: Send pre-approved template messages
- 📎 Media Support: Send and receive images, videos, audio, documents, and stickers
- 📍 Location Sharing: Send and receive location data
- 🤖 Handler System: Decorator-based message handlers with regex and custom filters
- 🔁 Context Management: Maintain conversation state across messages
- 🚀 Easy Setup: Simple initialization and intuitive API
Install the library using pip:
pip install --upgrade python-whatsapp-botTo use this library, you need:
- Phone Number ID: From your WhatsApp Business account
- Access Token: From the Facebook Developer Portal
Follow the official WhatsApp setup tutorial to obtain these credentials.
frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')Synchronous:
# Simple text messagewa_bot.send_message('2348145xxxxx', 'Hello, World!')
# With web preview disabledwa_bot.send_message('2348145xxxxx', 'Check this link: https://example.com', web_page_preview=False)Asynchronous:
importasyncioasyncdefmain():
# Async versionawaitwa_bot.asend_message('2348145xxxxx', 'Hello from async!')
asyncio.run(main())frompython_whatsapp_botimportInline_keyboard# Simple buttonsbuttons=Inline_keyboard(['Option 1', 'Option 2', 'Option 3'])
wa_bot.send_message(
'2348145xxxxx',
'Choose an option:',
reply_markup=buttons
)
# Custom button IDsfrompython_whatsapp_botimportInline_buttonbuttons=Inline_keyboard([
Inline_button('Yes', button_id='btn_yes'),
Inline_button('No', button_id='btn_no')
])
wa_bot.send_message('2348145xxxxx', 'Confirm?', reply_markup=buttons)frompython_whatsapp_botimportInline_list, List_item# Simple listlist_items= [
List_item('Pizza'),
List_item('Burger'),
List_item('Salad')
]
list_markup=Inline_list('Select Food', list_items)
wa_bot.send_message('2348145xxxxx', 'What would you like?', reply_markup=list_markup)
# List with descriptionslist_items= [
List_item('Premium Plan', _id='plan_premium', description='$99/month - All features'),
List_item('Basic Plan', _id='plan_basic', description='$29/month - Essential features')
]
list_markup=Inline_list('Choose Plan', list_items)
wa_bot.send_message('2348145xxxxx', 'Select a plan:', reply_markup=list_markup)
# Sectioned listsfrompython_whatsapp_botimportList_sectionsections= [
List_section('Appetizers', [
List_item('Spring Rolls'),
List_item('Garlic Bread')
]),
List_section('Main Course', [
List_item('Pasta'),
List_item('Steak')
])
]
list_markup=Inline_list('Menu', sections)
wa_bot.send_message('2348145xxxxx', 'Our menu:', reply_markup=list_markup)# Simple templatewa_bot.send_template_message('2348145xxxxx', 'hello_world')
# Template with componentscomponents= [
{
"type": "body",
"parameters": [
{"type": "text", "text": "John Doe"},
{"type": "text", "text": "Order #12345"}
]
}
]
wa_bot.send_template_message(
'2348145xxxxx',
'order_confirmation',
components=components,
language_code='en_US'
)
# Async versionawaitwa_bot.asend_template_message('2348145xxxxx', 'hello_world')# Send image from URLwa_bot.send_media_message(
'2348145xxxxx',
'https://example.com/image.jpg',
caption='Check this out!'
)
# Async versionawaitwa_bot.asend_media_message(
'2348145xxxxx',
'https://example.com/image.jpg',
caption='Amazing photo!'
)
# Download received mediamedia_id='MEDIA_ID_FROM_WEBHOOK'file_path=wa_bot.download_media(media_id, '/downloads')
print(f'Media saved to: {file_path}')
# Async downloadfile_path=awaitwa_bot.adownload_media(media_id, '/downloads')frompython_whatsapp_bot.messageimportmessage_locationmessage_location(
wa_bot.msg_url,
wa_bot.token,
'2348145xxxxx',
latitude='37.7749',
longitude='-122.4194',
location_name='San Francisco',
location_address='Golden Gate Bridge'
)WhatsApp sends incoming messages to your webhook URL. You need to:
- Register your webhook URL in the Facebook Developer Portal
- Verify the webhook with a GET request handler
- Process POST requests containing message updates
fromflaskimportFlask, requestapp=Flask(__name__)
# Simple message handler@wa_bot.on_message()defhandle_message(update, context):
# Echo the messageupdate.reply_message(f"You said: {update.message_text}")
# Regex-based handler@wa_bot.on_message(regex=r'^/start')defhandle_start(update, context):
update.reply_message('Welcome! How can I help you?')
# Interactive message handler@wa_bot.on_interactive_message()defhandle_button(update, context):
button_id=update.message_textifbutton_id=='btn_yes':
update.reply_message('Great! Proceeding...')
elifbutton_id=='btn_no':
update.reply_message('Okay, cancelled.')
# Image handler@wa_bot.on_image_message()defhandle_image(update, context):
media_id=update.media_file_idupdate.reply_message(f'Thanks for the image! ID: {media_id}')
# Location handler@wa_bot.on_location_message()defhandle_location(update, context):
lat=update.loc_latitudelon=update.loc_longitudeupdate.reply_message(f'Received location: {lat}, {lon}')
# Webhook endpoint@app.route('/webhook', methods=['POST'])defwebhook():
data=request.get_json()
wa_bot.process_update(data)
return'OK', 200@app.route('/webhook', methods=['GET'])defverify_webhook():
mode=request.args.get('hub.mode')
token=request.args.get('hub.verify_token')
challenge=request.args.get('hub.challenge')
ifmode=='subscribe'andtoken=='YOUR_VERIFY_TOKEN':
returnchallenge, 200return'Forbidden', 403if__name__=='__main__':
app.run(port=5000)importasynciofromaiohttpimportweb# Async handler@wa_bot.on_message()asyncdefhandle_message_async(update, context):
# Perform async operationsawaitasyncio.sleep(1) # Simulate async workawaitupdate.reply_message('Processed asynchronously!')
# Async webhookasyncdefwebhook_handler(request):
data=awaitrequest.json()
awaitwa_bot.dispatcher.aprocess_update(data)
returnweb.Response(text='OK')
app=web.Application()
app.router.add_post('/webhook', webhook_handler)
if__name__=='__main__':
web.run_app(app, port=5000)# Store user data in context@wa_bot.on_message(regex=r'^/setname (.+)')defset_name(update, context):
name=update.message_text.split(' ', 1)[1]
context.user_data['name'] =nameupdate.reply_message(f'Name set to: {name}')
@wa_bot.on_message(regex=r'^/getname')defget_name(update, context):
name=context.user_data.get('name', 'Not set')
update.reply_message(f'Your name is: {name}')
# Multi-step conversations@wa_bot.on_message(regex=r'^/register')defstart_registration(update, context):
update.reply_message('Please enter your name:')
wa_bot.set_next_step(update, get_user_name)
defget_user_name(update, context):
context.user_data['name'] =update.message_textupdate.reply_message('Please enter your email:')
wa_bot.set_next_step(update, get_user_email)
defget_user_email(update, context):
context.user_data['email'] =update.message_textname=context.user_data['name']
email=context.user_data['email']
update.reply_message(f'Registration complete!\nName: {name}\nEmail: {email}')# Custom filter functiondefis_premium_user(message_text):
# Your logic herereturnmessage_text.startswith('!')
@wa_bot.on_message(func=is_premium_user)defhandle_premium(update, context):
update.reply_message('Premium command received!')# Handler that runs for every message@wa_bot.on_message(persistent=True)deflog_all_messages(update, context):
print(f'Message from {update.user_phone_number}: {update.message_text}')# Syncwa_bot.mark_as_read(message_update)
# Asyncawaitwa_bot.amark_as_read(message_update)
# Auto-mark on initializationwa_bot=Whatsapp(number_id='...', token='...', mark_as_read=True) # DefaultThe library includes comprehensive test suites for both sync and async functions.
# Install dev dependencies
pip install pytest pytest-asyncio pytest-httpx
# Run all tests
pytest
# Run specific test file
pytest tests/test_message.py
# Run async tests only
pytest tests/test_message_async.py
# With coverage
pytest --cov=python_whatsapp_botMain bot class for interacting with WhatsApp Cloud API.
Methods:
send_message()/asend_message()- Send text messagessend_template_message()/asend_template_message()- Send template messagessend_media_message()/asend_media_message()- Send media filesmark_as_read()/amark_as_read()- Mark messages as readdownload_media()/adownload_media()- Download media filesget_media_url()/aget_media_url()- Get media URLsprocess_update()- Process incoming webhook updates
Represents an incoming message update.
Attributes:
user_phone_number- Sender's phone numberuser_display_name- Sender's display namemessage_text- Text content of messagemessage_id- Unique message identifiermedia_file_id- Media file ID (for media messages)loc_latitude,loc_longitude- Location coordinates
Methods:
reply_message()- Reply to the messagereply_media()- Reply with media
Inline_keyboard(buttons)- Create button markupInline_button(text, button_id)- Single buttonInline_list(button_text, list_items)- List markupList_item(title, _id, description)- List itemList_section(title, items_list)- List sectionInlineLocationRequest(text)- Location request button
Import Errors:
pip install --upgrade python-whatsapp-bot httpxWebhook Not Receiving Messages:
- Verify webhook URL is registered in Facebook Developer Portal
- Ensure URL is publicly accessible (use ngrok for local testing)
- Check webhook verification token matches
Message Not Sending:
- Verify phone number format (include country code without '+' or '00')
- Check access token is valid
- Ensure phone number is registered with WhatsApp Business
Contributions are welcome! This is an open-source project under the MIT License.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- All contributors to this project
- WhatsApp Business Cloud API team
- The Python community
If you encounter any issues or have questions:
- Open an issue on GitHub
- Check the documentation
- Review WhatsApp API documentation
Made with ❤️ by Radi