Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

python-whatsapp-bot

A modern, feature-rich Python library for building WhatsApp bots using the WhatsApp Business Cloud API.

Made in NigeriaDownloadsDownloadsDownloads

🔗 Links

✨ Key Features

  • 🔄 Sync & Async Support: Mirror async versions of all functions (e.g., send_message and asend_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

📦 Installation

Install the library using pip:

pip install --upgrade python-whatsapp-bot

🚀 Quick Start

Setting Up

To use this library, you need:

  1. Phone Number ID: From your WhatsApp Business account
  2. Access Token: From the Facebook Developer Portal

Follow the official WhatsApp setup tutorial to obtain these credentials.

Basic Initialization

frompython_whatsapp_botimportWhatsapp# Initialize the botwa_bot=Whatsapp(number_id='YOUR_PHONE_NUMBER_ID', token='YOUR_ACCESS_TOKEN')

📖 Usage Guide

Sending Text Messages

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())

Interactive Messages

Buttons

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)

Lists

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)

Template Messages

# 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')

Media Messages

# 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')

Location Messages

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'
)

🎯 Handling Incoming Messages

Setting Up Webhooks

WhatsApp sends incoming messages to your webhook URL. You need to:

  1. Register your webhook URL in the Facebook Developer Portal
  2. Verify the webhook with a GET request handler
  3. Process POST requests containing message updates

Message Handlers

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)

Async Message Handlers

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)

Context and Conversation Management

# 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}')

🔧 Advanced Features

Custom Filters

# 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!')

Persistent Handlers

# 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}')

Mark Messages as Read

# 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) # Default

🧪 Testing

The 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_bot

📚 API Reference

Main Classes

Whatsapp(number_id, token, mark_as_read=True)

Main bot class for interacting with WhatsApp Cloud API.

Methods:

  • send_message() / asend_message() - Send text messages
  • send_template_message() / asend_template_message() - Send template messages
  • send_media_message() / asend_media_message() - Send media files
  • mark_as_read() / amark_as_read() - Mark messages as read
  • download_media() / adownload_media() - Download media files
  • get_media_url() / aget_media_url() - Get media URLs
  • process_update() - Process incoming webhook updates

Update

Represents an incoming message update.

Attributes:

  • user_phone_number - Sender's phone number
  • user_display_name - Sender's display name
  • message_text - Text content of message
  • message_id - Unique message identifier
  • media_file_id - Media file ID (for media messages)
  • loc_latitude, loc_longitude - Location coordinates

Methods:

  • reply_message() - Reply to the message
  • reply_media() - Reply with media

Markup Classes

  • Inline_keyboard(buttons) - Create button markup
  • Inline_button(text, button_id) - Single button
  • Inline_list(button_text, list_items) - List markup
  • List_item(title, _id, description) - List item
  • List_section(title, items_list) - List section
  • InlineLocationRequest(text) - Location request button

🐛 Troubleshooting

Common Issues

Import Errors:

pip install --upgrade python-whatsapp-bot httpx

Webhook Not Receiving Messages:

  1. Verify webhook URL is registered in Facebook Developer Portal
  2. Ensure URL is publicly accessible (use ngrok for local testing)
  3. Check webhook verification token matches

Message Not Sending:

  1. Verify phone number format (include country code without '+' or '00')
  2. Check access token is valid
  3. Ensure phone number is registered with WhatsApp Business

🤝 Contributing

Contributions are welcome! This is an open-source project under the MIT License.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Credits

  • All contributors to this project
  • WhatsApp Business Cloud API team
  • The Python community

📮 Support

If you encounter any issues or have questions:


Made with ❤️ by Radi

About

A whatsapp client library for python using the new WhatsApp cloud API.

Resources

Stars

32 stars

Watchers

3 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages