whatsapp_cloud_flutter 1.1.3
whatsapp_cloud_flutter: ^1.1.3 copied to clipboard
A comprehensive Flutter package providing type-safe WhatsApp Cloud API integration. Send messages, handle webhooks, manage media, and build chat interfaces with ease.
WhatsApp Cloud Flutter #
A comprehensive Flutter package that provides a type-safe, easy-to-use wrapper around Meta's WhatsApp Cloud API. This package enables Flutter developers to integrate WhatsApp messaging capabilities into their applications with minimal effort, handling the complexities of API interactions, authentication, and message formatting.
Developed by Israel Biselu from SwahiliConnect
π Why Choose WhatsApp Cloud Flutter? #
- π Production Ready: Built with enterprise-grade reliability and scalability
- π‘οΈ Type Safe: Full TypeScript-like type safety for all API interactions
- π± Flutter Native: Designed specifically for Flutter with native widget support
- π§ Easy Integration: Get started in minutes with minimal configuration
- π Comprehensive: Covers all WhatsApp Cloud API features and message types
- π Secure: Built-in security features including webhook verification
- β‘ Performance: Optimized with rate limiting, retry mechanisms, and efficient networking
π Features #
π± Complete Message Support #
- Text Messages - Rich text with URL previews and formatting
- Media Messages - Images, videos, audio, documents, and stickers
- Interactive Messages - Buttons, lists, and call-to-action components
- Advanced Interactive - CTA URLs, location requests, address collection
- Location Messages - GPS coordinates with names and addresses
- Contact Cards - vCard format contact sharing
- Template Messages - Business templates with dynamic content
- Reaction Messages - Emoji reactions to messages
οΏ½οΈ Developer Experience #
- π§ Simple Setup - Initialize in 3 lines of code
- π Template Management - Create, retrieve, and send templates
- π Media Handling - Upload, download, and manage media files
- π Webhook Integration - Real-time message and status updates
- π Analytics & Monitoring - Built-in metrics and performance tracking
- πͺ΅ Comprehensive Logging - Debug-friendly logging at multiple levels
π Enterprise Features #
- β‘ Rate Limiting - Automatic API quota management
- π Retry Logic - Exponential backoff for failed requests
- π‘οΈ Security - Webhook signature verification and token management
- π Scalability - Designed for high-volume messaging scenarios
- π― Error Handling - Detailed error types and recovery strategies
π¨ UI Components (Bonus!) #
- MessageComposer - Ready-to-use message input widget
- TemplateSelector - Template picker with preview
- ChatBubble - Customizable message bubbles
- MediaPicker - Integrated media selection
π¦ Installation #
Add this package to your pubspec.yaml
:
dependencies:
whatsapp_cloud_flutter: ^1.0.0
Install it:
flutter pub get
Import it:
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
π Quick Start #
Step 1: Get Your Credentials #
Before using this package, you need:
- Meta Developer Account - Create one here
- WhatsApp Business Account - Set up in Meta Business Manager
- WhatsApp Business App - Create in Meta Developers Console
- Phone Number ID - Found in your app settings
- Access Token - Generate in Meta Developers Console
π‘ Pro Tip: Start with a temporary access token for testing, then implement permanent tokens for production.
Step 2: Initialize the Client #
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
// Basic initialization
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
);
// Advanced initialization with custom configuration
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
config: WhatsAppApiConfig(
logLevel: LogLevel.debug,
environment: Environment.production,
retryPolicy: RetryPolicy(maxRetries: 3),
connectTimeout: Duration(seconds: 30),
),
);
Step 3: Send Your First Message #
try {
final response = await whatsapp.messageService.sendTextMessage(
recipient: '+1234567890', // Include country code
text: 'Hello from Flutter! π',
previewUrl: true,
);
if (response.successful) {
print('β
Message sent! ID: ${response.messageId}');
} else {
print('β Failed: ${response.errorMessage}');
}
} catch (e) {
print('π¨ Error: $e');
}
That's it! You've sent your first WhatsApp message from Flutter! π
π Comprehensive Usage Guide #
π¬ Text Messages #
// Simple text message
await whatsapp.messageService.sendTextMessage(
recipient: '+1234567890',
text: 'Hello World!',
);
// Text with URL preview
await whatsapp.messageService.sendTextMessage(
recipient: '+1234567890',
text: 'Check out this amazing Flutter package: https://pub.flutter-io.cn/packages/whatsapp_cloud_flutter',
previewUrl: true,
);
// Formatted text (WhatsApp formatting)
await whatsapp.messageService.sendTextMessage(
recipient: '+1234567890',
text: '*Bold text* _italic text_ ~strikethrough~ ```monospace```',
);
πΌοΈ Media Messages #
// Send image from URL
await whatsapp.messageService.sendImageMessage(
recipient: '+1234567890',
source: MediaSource.url,
mediaUrl: 'https://example.com/image.jpg',
caption: 'Beautiful sunset! π
',
);
// Send image from local file
final file = File('path/to/local/image.jpg');
final uploadResponse = await whatsapp.mediaService.uploadMedia(
mediaType: MediaType.image,
file: file,
);
if (uploadResponse.successful) {
await whatsapp.messageService.sendImageMessage(
recipient: '+1234567890',
source: MediaSource.id,
mediaId: uploadResponse.mediaId!,
caption: 'Image from my phone!',
);
}
// Send document
await whatsapp.messageService.sendDocumentMessage(
recipient: '+1234567890',
source: MediaSource.url,
mediaUrl: 'https://example.com/document.pdf',
filename: 'important_document.pdf',
caption: 'Please review this document',
);
// Send video
await whatsapp.messageService.sendVideoMessage(
recipient: '+1234567890',
source: MediaSource.url,
mediaUrl: 'https://example.com/video.mp4',
caption: 'Product demo video',
);
// Send audio
await whatsapp.messageService.sendAudioMessage(
recipient: '+1234567890',
source: MediaSource.url,
mediaUrl: 'https://example.com/audio.mp3',
);
πΊοΈ Location Messages #
// Send location
await whatsapp.messageService.sendLocationMessage(
recipient: '+1234567890',
latitude: 37.7749,
longitude: -122.4194,
name: 'San Francisco Office',
address: '123 Market St, San Francisco, CA 94103',
);
π Contact Messages #
// Send contact card
await whatsapp.messageService.sendContactMessage(
recipient: '+1234567890',
contacts: [
Contact(
name: ContactName(
formattedName: 'John Doe',
firstName: 'John',
lastName: 'Doe',
),
phones: [
ContactPhone(
phone: '+1234567890',
type: 'WORK',
),
],
emails: [
ContactEmail(
email: 'john.doe@company.com',
type: 'WORK',
),
],
),
],
);
π Template Messages #
// Send a simple template
await whatsapp.templateService.sendTemplate(
recipient: '+1234567890',
templateName: 'hello_world',
language: 'en_US',
);
// Send template with parameters
await whatsapp.templateService.sendTemplate(
recipient: '+1234567890',
templateName: 'appointment_reminder',
language: 'en_US',
components: [
TemplateComponent(
type: ComponentType.body,
parameters: [
TextParameter(text: 'John Doe'),
DateTimeParameter(datetime: DateTime.now().add(Duration(days: 2))),
],
),
TemplateComponent(
type: ComponentType.button,
subType: 'quick_reply',
index: 0,
parameters: [
TextParameter(text: 'Confirm'),
],
),
],
);
// Get available templates
final templates = await whatsapp.templateService.getTemplates();
for (final template in templates) {
print('Template: ${template.name} - Status: ${template.status}');
}
π― Interactive Messages #
// Send button message
final buttonMessage = InteractiveMessage(
recipient: '+1234567890',
interactiveType: InteractiveType.button,
body: BodyComponent(text: 'Choose your preferred option:'),
action: ActionComponent(
buttons: [
ButtonComponent(id: 'option_1', title: 'Option 1'),
ButtonComponent(id: 'option_2', title: 'Option 2'),
ButtonComponent(id: 'option_3', title: 'Option 3'),
],
),
);
await whatsapp.messageService.sendMessage(buttonMessage);
// Send list message
final listMessage = InteractiveMessage(
recipient: '+1234567890',
interactiveType: InteractiveType.list,
body: BodyComponent(text: 'Select from our menu:'),
action: ActionComponent(
buttonText: 'View Menu',
sections: [
ListSection(
title: 'Main Courses',
rows: [
ListRow(id: 'pasta', title: 'Pasta', description: 'Delicious Italian pasta'),
ListRow(id: 'pizza', title: 'Pizza', description: 'Wood-fired pizza'),
],
),
ListSection(
title: 'Desserts',
rows: [
ListRow(id: 'tiramisu', title: 'Tiramisu', description: 'Classic Italian dessert'),
],
),
],
),
);
await whatsapp.messageService.sendMessage(listMessage);
π Message Status Tracking #
// Mark message as read
await whatsapp.messageService.markMessageAsRead(
messageId: 'wamid.HBgNMTc3...',
);
// Send reaction to a message
await whatsapp.messageService.sendReaction(
recipient: '+1234567890',
messageId: 'wamid.HBgNMTc3...',
emoji: 'π',
);
// Remove reaction
await whatsapp.messageService.sendReaction(
recipient: '+1234567890',
messageId: 'wamid.HBgNMTc3...',
emoji: '', // Empty string removes reaction
);
π Media Management #
// Upload media from file
final file = File('path/to/image.jpg');
final uploadResponse = await whatsapp.mediaService.uploadMedia(
mediaType: MediaType.image,
file: file,
);
if (uploadResponse.successful) {
print('Media uploaded! ID: ${uploadResponse.mediaId}');
// Use the media ID to send messages
await whatsapp.messageService.sendImageMessage(
recipient: '+1234567890',
source: MediaSource.id,
mediaId: uploadResponse.mediaId!,
caption: 'Uploaded image',
);
}
// Download media
final downloadResponse = await whatsapp.mediaService.downloadMedia(
mediaId: 'MEDIA_ID_HERE',
);
if (downloadResponse.successful) {
final mediaBytes = downloadResponse.data;
// Save to file or display in your app
}
// Get media info
final mediaInfo = await whatsapp.mediaService.getMediaInfo('MEDIA_ID_HERE');
print('Media size: ${mediaInfo.fileSize} bytes');
print('Media type: ${mediaInfo.mimeType}');
π Webhook Integration #
Set up webhooks to receive real-time updates:
// Register message handler
whatsapp.webhookService.registerMessageHandler((messageEvent) {
print('π¨ New message from ${messageEvent.from}: ${messageEvent.text}');
// Auto-reply example
if (messageEvent.text?.toLowerCase() == 'hello') {
whatsapp.messageService.sendTextMessage(
recipient: messageEvent.from,
text: 'Hi there! How can I help you today?',
);
}
});
// Register status update handler
whatsapp.webhookService.registerStatusHandler((statusEvent) {
print('π Message ${statusEvent.messageId} status: ${statusEvent.status}');
switch (statusEvent.status) {
case MessageStatus.delivered:
print('β
Message delivered');
break;
case MessageStatus.read:
print('π Message read');
break;
case MessageStatus.failed:
print('β Message failed: ${statusEvent.error}');
break;
}
});
// Register interactive message handler
whatsapp.webhookService.registerInteractiveHandler((interactiveEvent) {
print('π― Button clicked: ${interactiveEvent.buttonId}');
// Handle button responses
switch (interactiveEvent.buttonId) {
case 'confirm':
whatsapp.messageService.sendTextMessage(
recipient: interactiveEvent.from,
text: 'Great! Your booking is confirmed.',
);
break;
case 'cancel':
whatsapp.messageService.sendTextMessage(
recipient: interactiveEvent.from,
text: 'No problem! Let me know if you need anything else.',
);
break;
}
});
// Process incoming webhook (in your web server)
app.post('/webhook', (req, res) {
final payload = req.body;
whatsapp.webhookService.processWebhook(payload);
res.status(200).send('OK');
});
// Webhook verification (required by Meta)
app.get('/webhook', (req, res) {
final mode = req.query['hub.mode'];
final token = req.query['hub.verify_token'];
final challenge = req.query['hub.challenge'];
final result = whatsapp.webhookService.verifyWebhook(
mode: mode,
verifyToken: token,
challenge: challenge,
expectedToken: 'YOUR_VERIFY_TOKEN',
);
res.send(result);
});
π¨ Flutter UI Components #
This package includes ready-to-use Flutter widgets to speed up your development:
import 'package:flutter/material.dart';
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
class ChatScreen extends StatelessWidget {
final WhatsAppCloudClient whatsapp;
final String recipient;
const ChatScreen({required this.whatsapp, required this.recipient});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('WhatsApp Chat')),
body: Column(
children: [
// Chat messages
Expanded(
child: ListView(
children: [
ChatBubble(
message: 'Hello! How can I help you?',
alignment: BubbleAlignment.left,
timestamp: DateTime.now(),
senderName: 'Support',
),
ChatBubble(
message: 'I need help with my order',
alignment: BubbleAlignment.right,
timestamp: DateTime.now(),
),
],
),
),
// Message composer
MessageComposer(
messageService: whatsapp.messageService,
recipient: recipient,
placeholder: 'Type your message...',
onMessageSent: (messageId) {
print('Message sent: $messageId');
// Update your UI
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $error')),
);
},
),
],
),
);
}
}
// Template selector widget
class TemplateScreen extends StatelessWidget {
final WhatsAppCloudClient whatsapp;
final String recipient;
const TemplateScreen({required this.whatsapp, required this.recipient});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Choose Template')),
body: TemplateSelector(
templateService: whatsapp.templateService,
recipient: recipient,
languageCode: 'en_US',
onTemplateSent: (messageId) {
Navigator.pop(context);
print('Template sent: $messageId');
},
onError: (error) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $error')),
);
},
),
);
}
}
π¨ Error Handling #
The package provides comprehensive error handling with specific exception types:
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
try {
final response = await whatsapp.messageService.sendTextMessage(
recipient: '+1234567890',
text: 'Hello World!',
);
if (response.successful) {
print('β
Success: ${response.messageId}');
} else {
print('β API Error: ${response.errorMessage}');
}
} on AuthException catch (e) {
// Authentication/authorization errors
print('π Auth Error: ${e.message}');
// Refresh token or re-authenticate
} on RateLimitException catch (e) {
// Rate limiting errors
print('β±οΈ Rate Limited: Retry after ${e.retryAfter} seconds');
// Implement backoff strategy
} on MediaException catch (e) {
// Media-specific errors (file too large, invalid format, etc.)
print('π Media Error: ${e.code} - ${e.message}');
// Handle media-specific issues
} on MessageException catch (e) {
// Message-specific errors (invalid recipient, content issues, etc.)
print('π¬ Message Error: ${e.code} - ${e.message}');
// Handle message validation issues
} on ApiException catch (e) {
// General API errors
print('π API Error: ${e.statusCode} - ${e.message}');
// Handle network/server issues
} on ValidationException catch (e) {
// Input validation errors
print('β
Validation Error: ${e.field} - ${e.message}');
// Handle input validation
} catch (e) {
// Unexpected errors
print('π¨ Unexpected Error: $e');
// Handle unknown errors gracefully
}
Retry Strategy Example #
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
Future<MessageResponse?> sendMessageWithRetry({
required String recipient,
required String text,
int maxRetries = 3,
}) async {
for (int attempt = 1; attempt <= maxRetries; attempt++) {
try {
final response = await whatsapp.messageService.sendTextMessage(
recipient: recipient,
text: text,
);
if (response.successful) {
return response; // Success!
}
// If this was the last attempt, return the failed response
if (attempt == maxRetries) {
return response;
}
} on RateLimitException catch (e) {
if (attempt == maxRetries) rethrow;
// Wait for the rate limit to reset
await Future.delayed(Duration(seconds: e.retryAfter));
continue;
} on ApiException catch (e) {
// For server errors (5xx), retry after a delay
if (e.statusCode >= 500 && attempt < maxRetries) {
await Future.delayed(Duration(seconds: attempt * 2));
continue;
}
rethrow;
} catch (e) {
// For other errors, don't retry
rethrow;
}
}
return null;
}
βοΈ Advanced Configuration #
Customize the client behavior with advanced configuration options:
final config = WhatsAppApiConfig(
// API settings
baseUrl: 'https://graph.facebook.com/v18.0', // API version
connectTimeout: Duration(seconds: 30),
receiveTimeout: Duration(seconds: 30),
// Environment
environment: Environment.production, // or Environment.sandbox
// Logging
logLevel: LogLevel.debug, // debug, info, warning, error, off
// Retry policy
retryPolicy: RetryPolicy(
maxRetries: 3,
initialBackoff: Duration(seconds: 1),
maxBackoff: Duration(seconds: 30),
),
// Rate limiting (optional - helps prevent quota issues)
rateLimitConfig: RateLimitConfig(
requestsPerMinute: 80,
requestsPerHour: 1000,
requestsPerDay: 10000,
),
);
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
config: config,
);
Environment-Specific Configuration #
// Development environment
final devConfig = WhatsAppApiConfig(
environment: Environment.sandbox,
logLevel: LogLevel.debug,
retryPolicy: RetryPolicy(maxRetries: 1), // Fail fast in dev
);
// Production environment
final prodConfig = WhatsAppApiConfig(
environment: Environment.production,
logLevel: LogLevel.warning, // Less verbose logging
retryPolicy: RetryPolicy(
maxRetries: 5,
initialBackoff: Duration(seconds: 2),
maxBackoff: Duration(minutes: 5),
),
rateLimitConfig: RateLimitConfig.businessLimits, // Higher limits
);
Security Configuration #
// For webhook signature verification
final securityConfig = SecurityConfig(
webhookSecret: 'YOUR_WEBHOOK_SECRET',
verifySignatures: true,
allowedOrigins: ['your-domain.com'],
);
// Initialize with security
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
securityConfig: securityConfig,
);
π Analytics & Monitoring #
Track your messaging performance with built-in analytics:
// Enable analytics
final analytics = WhatsAppAnalytics(
logger: Logger(), // Your logger instance
);
// Record events automatically or manually
analytics.recordMessageSent('text', Duration(milliseconds: 150));
analytics.recordError('rate_limit', '429');
// Get performance metrics
final stats = analytics.getSummaryReport();
print('Success rate: ${stats['performance']['success_rate_percent']}%');
print('Average response time: ${stats['performance']['average_response_time_ms']}ms');
// Message type breakdown
final messageStats = analytics.messageTypeStats;
messageStats.forEach((type, count) {
print('$type messages: $count');
});
// Error analysis
final errorStats = analytics.errorStats;
errorStats.forEach((error, count) {
print('$error errors: $count');
});
π Production Security Checklist #
β Authentication & Authorization #
- β Use permanent access tokens (not temporary ones)
- β Implement token refresh logic
- β Store tokens securely (not in code/version control)
- β Use environment variables or secure storage
- β Implement proper user authentication in your app
β Webhook Security #
- β Set up webhook signature verification
- β Use HTTPS for webhook URLs
- β Validate webhook payloads
- β Implement rate limiting on webhook endpoints
- β Set up proper error handling
β Input Validation #
- β Validate phone numbers (international format)
- β Sanitize user input before sending messages
- β Validate file uploads (size, type, content)
- β Implement content filtering if needed
β Error Handling #
- β Implement comprehensive error handling
- β Set up monitoring and alerting
- β Log errors securely (don't log sensitive data)
- β Implement fallback mechanisms
β Rate Limiting & Performance #
- β Configure appropriate rate limits
- β Implement message queuing for high volume
- β Set up monitoring for API quotas
- β Optimize media file sizes
// Example secure configuration
final secureConfig = WhatsAppApiConfig(
environment: Environment.production,
logLevel: LogLevel.warning, // Don't log sensitive data
retryPolicy: RetryPolicy(
maxRetries: 5,
initialBackoff: Duration(seconds: 2),
),
connectTimeout: Duration(seconds: 15),
receiveTimeout: Duration(seconds: 15),
);
// Secure token management
class TokenManager {
static Future<String> getAccessToken() async {
// Get from secure storage, not hardcoded
final prefs = await SharedPreferences.getInstance();
return prefs.getString('whatsapp_token') ?? '';
}
static Future<void> saveAccessToken(String token) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setString('whatsapp_token', token);
}
static Future<void> refreshToken() async {
// Implement token refresh logic
// Make API call to refresh token
// Save new token securely
}
}
π± Example Application #
The package includes a comprehensive example app that demonstrates all features. To run it:
git clone https://github.com/swahiliconnect/whatsapp_cloud_flutter.git
cd whatsapp_cloud_flutter/example
flutter pub get
flutter run
The example app includes:
- Configuration Setup - Easy credential management
- Text Messaging - Send messages with URL previews
- Location Sharing - Send GPS coordinates
- Media Upload - Handle images, videos, documents
- Template Management - Work with business templates
- Webhook Testing - Test webhook functionality
- Error Handling - See how errors are handled
- Real-time Logging - Monitor API interactions
Example App Screenshots #
Configuration | Messaging | Templates |
---|---|---|
![]() |
![]() |
![]() |
π οΈ Development & Testing #
Testing Your Integration #
- Use WhatsApp Test Numbers: Start with Meta's test phone numbers
- Verify Webhook Setup: Use tools like ngrok for local testing
- Test Error Scenarios: Simulate rate limits, invalid tokens, etc.
- Monitor API Usage: Keep track of your quotas and limits
Debugging Tips #
// Enable debug logging
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
config: WhatsAppApiConfig(
logLevel: LogLevel.debug, // See all API calls
),
);
// Test API connectivity
try {
final response = await whatsapp.messageService.sendTextMessage(
recipient: 'YOUR_TEST_NUMBER',
text: 'Test message',
);
print('API is working: ${response.successful}');
} catch (e) {
print('API issue: $e');
}
Unit Testing #
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
// Mock the client for testing
class MockWhatsAppClient extends Mock implements WhatsAppCloudClient {}
void main() {
group('WhatsApp Integration Tests', () {
late MockWhatsAppClient mockClient;
setUp(() {
mockClient = MockWhatsAppClient();
});
test('should send text message successfully', () async {
// Arrange
const recipient = '+1234567890';
const text = 'Test message';
final expectedResponse = MessageResponse(
successful: true,
messageId: 'test-id-123',
);
when(mockClient.messageService.sendTextMessage(
recipient: recipient,
text: text,
)).thenAnswer((_) async => expectedResponse);
// Act
final response = await mockClient.messageService.sendTextMessage(
recipient: recipient,
text: text,
);
// Assert
expect(response.successful, true);
expect(response.messageId, 'test-id-123');
});
});
}
π API Reference & Documentation #
Complete API Documentation #
- pub.flutter-io.cn Documentation - Complete API reference
- WhatsApp Cloud API Docs - Official Meta documentation
- GitHub Wiki - Detailed guides and tutorials
Supported WhatsApp Cloud API Version #
This package supports WhatsApp Cloud API v18.0 and is backward compatible with v16.0+.
Rate Limits & Quotas #
- Free Tier: 1,000 conversations/month
- Business Tier: Pay-per-conversation pricing
- API Limits: 80 messages/minute, 1,000 messages/hour
- Media Limits: 100MB file size, specific formats supported
π€ Contributing #
We welcome contributions! This is an open-source project maintained by SwahiliConnect.
How to Contribute #
- Fork the Project - Click the fork button on GitHub
- Create Feature Branch -
git checkout -b feature/AmazingFeature
- Write Tests - Ensure your code is tested
- Commit Changes -
git commit -m 'Add some AmazingFeature'
- Push to Branch -
git push origin feature/AmazingFeature
- Open Pull Request - Submit your changes for review
Development Setup #
# Clone the repository
git clone https://github.com/swahiliconnect/whatsapp_cloud_flutter.git
cd whatsapp_cloud_flutter
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run example app
cd example
flutter pub get
flutter run
Contribution Guidelines #
- β Follow Dart style guide
- β Write comprehensive tests for new features
- β Update documentation for API changes
- β Ensure backward compatibility when possible
- β Add examples for new features
π― Roadmap & Future Plans #
Upcoming Features #
- π¨ Enhanced UI Components - More customizable widgets
- π Advanced Analytics - Detailed reporting and insights
- π Message Sync - Two-way message synchronization
- π€ Bot Framework - Built-in chatbot capabilities
- π¦ Message Templates - Visual template builder
- π Multi-language Support - Localization helpers
Community Requests #
Vote for features on our GitHub Discussions!
β FAQ #
How do I get WhatsApp Cloud API access?
- Create a Meta Developer account
- Set up a WhatsApp Business account
- Create a WhatsApp Business App in Meta Developers Console
- Get your Phone Number ID and Access Token
- Set up webhook endpoints (optional but recommended)
Is this package free to use?
Yes! This package is completely free and open-source (MIT License). However, WhatsApp Cloud API has its own pricing:
- Free: 1,000 conversations per month
- Paid: Pay-per-conversation after free tier
Can I use this in production?
Absolutely! This package is production-ready and includes:
- β Comprehensive error handling
- β Rate limiting protection
- β Security features
- β Monitoring and analytics
- β Battle-tested with real applications
What's the difference between WhatsApp Business API and Cloud API?
- Business API: Self-hosted, complex setup, enterprise features
- Cloud API: Meta-hosted, easy setup, perfect for most use cases
- This package: Designed for Cloud API (easier and more accessible)
How do I handle large message volumes?
For high-volume messaging:
- Implement message queuing
- Use multiple phone numbers
- Configure appropriate rate limits
- Monitor API quotas
- Consider WhatsApp Business API for enterprise needs
π Support & Community #
Get Help #
- π Documentation - Complete API reference
- π¬ GitHub Discussions - Community Q&A
- π Issue Tracker - Bug reports and feature requests
- π§ Email Support - Direct support from SwahiliConnect
Community #
Join our growing community of developers using WhatsApp Cloud Flutter!
- β Star the repo if you find it useful
- π¦ Follow @SwahiliConnect for updates
- πΌ LinkedIn - Professional updates
- π Website - More about SwahiliConnect
π¨βπ» About the Author #
This package is developed and maintained by Israel Biselu from SwahiliConnect - a software development company focused on building solutions that connect communities across Africa.
SwahiliConnect Mission #
We believe in the power of technology to bridge communication gaps and enable businesses to reach their customers more effectively. This WhatsApp Cloud Flutter package is part of our commitment to providing high-quality, open-source tools for the developer community.
π License #
This project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2025 SwahiliConnect - Israel Biselu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
π Complete Implementation Guides #
π Webhook Server Setup #
The package includes webhook processing logic, but you'll need a server to receive webhooks. Here's a complete implementation:
Click to see complete webhook server code
// Add to pubspec.yaml: shelf: ^1.4.0
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
class WhatsAppWebhookServer {
final WhatsAppCloudClient whatsapp;
final String verifyToken;
WhatsAppWebhookServer({required this.whatsapp, required this.verifyToken});
Future<void> start({String host = '0.0.0.0', int port = 8080}) async {
final handler = Pipeline()
.addMiddleware(logRequests())
.addHandler(_handleRequest);
final server = await serve(handler, host, port);
print('π Webhook server running on ${server.address.host}:${server.port}');
_setupWebhookHandlers();
}
Future<Response> _handleRequest(Request request) async {
if (request.method == 'GET' && request.url.path == 'webhook') {
return _handleVerification(request);
} else if (request.method == 'POST' && request.url.path == 'webhook') {
return await _handleWebhookEvent(request);
}
return Response.notFound('Endpoint not found');
}
Response _handleVerification(Request request) {
final params = request.url.queryParameters;
final mode = params['hub.mode'];
final token = params['hub.verify_token'];
final challenge = params['hub.challenge'];
if (mode == 'subscribe' && token == verifyToken) {
print('β
Webhook verification successful!');
return Response.ok(challenge);
}
print('β Webhook verification failed!');
return Response.forbidden('Verification failed');
}
Future<Response> _handleWebhookEvent(Request request) async {
try {
final body = await request.readAsString();
print('π¨ Received webhook: $body');
whatsapp.webhookService.processWebhook(body);
return Response.ok('EVENT_RECEIVED');
} catch (e) {
print('β Error processing webhook: $e');
return Response.internalServerError();
}
}
void _setupWebhookHandlers() {
whatsapp.webhookService.registerMessageHandler((event) {
print('π± New message from ${event.from}: ${event.text}');
// Auto-reply example
if (event.text?.toLowerCase().contains('hello') == true) {
whatsapp.messageService.sendTextMessage(
recipient: event.from,
text: 'Hello! Thanks for your message.',
);
}
});
whatsapp.webhookService.registerStatusHandler((event) {
print('π Message ${event.messageId} status: ${event.status}');
});
}
}
// Usage
void main() async {
final whatsapp = WhatsAppCloudClient(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
);
final server = WhatsAppWebhookServer(
whatsapp: whatsapp,
verifyToken: 'your_secure_verify_token',
);
await server.start(port: 8080);
}
Setup Steps:
- Create webhook server file with code above
- Run:
dart webhook_server.dart
- Use ngrok for testing:
ngrok http 8080
- Configure webhook URL in Meta Developer Console
- Set verify token and subscribe to
messages
,message_deliveries
πΈ Media Upload Implementation #
The media service is fully functional. Here's how to integrate with Flutter's image picker:
Click to see complete media upload implementation
// Add to pubspec.yaml:
// image_picker: ^1.0.0
// file_picker: ^4.6.0
import 'dart:io';
import 'dart:typed_data';
import 'package:image_picker/image_picker.dart';
import 'package:whatsapp_cloud_flutter/whatsapp_cloud_flutter.dart';
class MediaUploadManager {
final WhatsAppCloudClient _client;
final ImagePicker _imagePicker = ImagePicker();
MediaUploadManager({required String phoneNumberId, required String accessToken})
: _client = WhatsAppCloudClient(phoneNumberId: phoneNumberId, accessToken: accessToken);
// Upload and send image from gallery
Future<bool> pickAndSendImage(String recipient) async {
try {
final XFile? image = await _imagePicker.pickImage(source: ImageSource.gallery);
if (image == null) return false;
final bytes = await image.readAsBytes();
// Upload to WhatsApp
final uploadResponse = await _client.mediaService.uploadMediaBytes(
mediaType: MediaType.image,
bytes: bytes,
mimeType: 'image/jpeg',
filename: image.name,
);
if (uploadResponse.successful) {
// Send the uploaded image
final messageResponse = await _client.messageService.sendImageMessage(
recipient: recipient,
source: MediaSource.id,
mediaId: uploadResponse.mediaId!,
caption: 'Image from Flutter app!',
);
return messageResponse.successful;
}
return false;
} catch (e) {
print('Error: $e');
return false;
}
}
// Upload from file path
Future<String?> uploadFromFile(String filePath, MediaType mediaType) async {
try {
final file = File(filePath);
final response = await _client.mediaService.uploadMedia(
mediaType: mediaType,
file: file,
);
return response.successful ? response.mediaId : null;
} catch (e) {
print('Upload error: $e');
return null;
}
}
// Upload from URL
Future<String?> uploadFromUrl(String url, MediaType mediaType) async {
try {
final response = await _client.mediaService.uploadMediaFromUrl(
mediaType: mediaType,
url: url,
);
return response.successful ? response.mediaId : null;
} catch (e) {
print('Upload error: $e');
return null;
}
}
}
// Usage in Flutter widget
class MediaUploadDemo extends StatefulWidget {
@override
_MediaUploadDemoState createState() => _MediaUploadDemoState();
}
class _MediaUploadDemoState extends State<MediaUploadDemo> {
final _mediaManager = MediaUploadManager(
phoneNumberId: 'YOUR_PHONE_NUMBER_ID',
accessToken: 'YOUR_ACCESS_TOKEN',
);
Future<void> _sendImage() async {
final success = await _mediaManager.pickAndSendImage('+1234567890');
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(success ? 'β
Image sent!' : 'β Failed to send')),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: _sendImage,
child: Text('Pick & Send Image'),
),
),
);
}
}
Media Type Limits:
- Images: 5MB (JPEG, PNG)
- Videos: 16MB (MP4, 3GPP)
- Audio: 16MB (AAC, M4A, AMR, MP3, OGG)
- Documents: 100MB (PDF, DOC, DOCX, etc.)
- Stickers: 100KB (WebP)
π Template Management #
Templates must be created in Meta Business Manager first, then approved before use:
Click to see complete template management guide
Step 1: Create Templates in Meta Business Manager
- Go to Meta Business Manager
- Navigate to WhatsApp Manager β Message Templates
- Click "Create Template"
- Fill in details and wait for approval (24-48 hours)
Step 2: Use Templates in Code
class TemplateManager {
final WhatsAppCloudClient _client;
TemplateManager({required String phoneNumberId, required String accessToken})
: _client = WhatsAppCloudClient(phoneNumberId: phoneNumberId, accessToken: accessToken);
// Send simple template (no parameters)
Future<bool> sendWelcomeTemplate(String recipient) async {
try {
final response = await _client.templateService.sendTemplate(
recipient: recipient,
templateName: 'hello_world', // Must match your approved template
language: 'en_US',
);
return response.successful;
} catch (e) {
print('Template error: $e');
return false;
}
}
// Send template with parameters
Future<bool> sendOrderConfirmation({
required String recipient,
required String customerName,
required String orderNumber,
}) async {
try {
// Template body: "Hi {{1}}, your order {{2}} is confirmed!"
final response = await _client.templateService.sendTemplate(
recipient: recipient,
templateName: 'order_confirmation',
language: 'en_US',
components: [
// Component implementation depends on your package's template component classes
// Check the package documentation for exact syntax
],
);
return response.successful;
} catch (e) {
print('Template error: $e');
return false;
}
}
// List your approved templates
Future<void> listTemplates() async {
try {
final templates = await _client.templateService.getTemplates();
print('π Your templates:');
for (final template in templates) {
print('- ${template['name']} (${template['status']})');
}
} catch (e) {
print('Error: $e');
}
}
}
Template Categories:
- UTILITY: Order confirmations, appointment reminders (higher approval rate)
- MARKETING: Promotions, newsletters (stricter approval)
- AUTHENTICATION: OTP codes, verification (fastest approval)
Template Approval Tips:
- Use clear, professional language
- Avoid promotional language in UTILITY templates
- Include proper variable placeholders {{1}}, {{2}}
- Follow WhatsApp's content policy
π§ First-Time Setup Checklist #
Prerequisites:
- β Meta Developer Account
- β WhatsApp Business Account
- β WhatsApp Business App created
- β Phone Number verified
- β Access Token generated
Basic Setup:
- β Add package to pubspec.yaml
- β Initialize WhatsAppCloudClient
- β Test basic text message sending
- β Verify recipient receives message
Advanced Setup (Optional):
- β Set up webhook server (for receiving messages)
- β Configure media upload (for sending files)
- β Create and approve templates (for business messaging)
- β Implement error handling and logging
- β Set up production security
Testing:
- β Send test message to your own number
- β Test webhook with ngrok
- β Upload and send test media
- β Verify template approval and sending
Made with β€οΈ by SwahiliConnect
β Star us on GitHub β’ π Report Bug β’ π‘ Request Feature