Integrating WhatsApp Business API for Sales Automation
- Mokshit Jain
- Backend Development , Integrations
- 25 Aug, 2025
In traditional sales workflows, creating quotations can be a tedious process involving manual data entry, switching between applications, and repetitive copying. By integrating WhatsApp Business API directly with legacy accounting systems, I reduced quotation creation time from 5 minutes to under 1 minute—a 5x productivity improvement.
The Problem
Before automation, the sales quotation workflow looked like this:
- Receive customer inquiry via WhatsApp/phone
- Open accounting software (legacy desktop application)
- Search products manually in the catalog
- Calculate totals in a spreadsheet or calculator
- Generate quotation PDF using accounting software
- Switch to WhatsApp manually to send the PDF
- Copy-paste details into WhatsApp message
Time per quotation: 5+ minutes
With 100+ quotations daily, this consumed significant sales time and was prone to errors.
The Solution: WhatsApp-First Automation
The new workflow:
- Customer sends inquiry via WhatsApp
- AI extracts requirements from the message
- System searches catalog automatically via API
- Quotation generates instantly
- WhatsApp sends PDF and summary automatically
Time per quotation: < 1 minute
WhatsApp Business API Setup
1. Get Access
First, you need access to WhatsApp Business API:
- Apply through Meta Business
- Or use a Business Solution Provider (BSP) like Twilio, MessageBird, or 360dialog
- For development, use Meta’s Graph API
2. Get Credentials
You’ll need:
- Phone Number ID: Your WhatsApp business number
- Access Token: For API authentication
- Business Account ID: Your WhatsApp Business Account ID
- Webhook URL: Endpoint to receive messages
3. Verify Webhook
WhatsApp sends messages to your webhook URL. Set this up first:
from fastapi import FastAPI, Request, BackgroundTasks
from fastapi.responses import JSONResponse
app = FastAPI()
WHATSAPP_VERIFY_TOKEN = "your_secret_token"
@app.get("/webhook/whatsapp")
async def verify_webhook(request: Request):
"""Meta's webhook verification"""
mode = request.query_params.get("hub.mode")
token = request.query_params.get("hub.verify_token")
challenge = request.query_params.get("hub.challenge")
if mode == "subscribe" and token == WHATSAPP_VERIFY_TOKEN:
return JSONResponse(content=int(challenge))
return JSONResponse(status_code=403, content={"error": "Forbidden"})
Receiving Messages
from pydantic import BaseModel
import httpx
class WhatsAppMessage(BaseModel):
from_number: str
message_body: str
message_id: str
@app.post("/webhook/whatsapp")
async def receive_message(request: Request, background_tasks: BackgroundTasks):
"""Handle incoming WhatsApp messages"""
data = await request.json()
try:
# Extract message from webhook payload
entry = data["entry"][0]
changes = entry["changes"][0]
value = changes["value"]
if "messages" in value:
message = value["messages"][0]
phone_number = message["from"]
# Get message text
text_body = message["text"]["body"]
# Process in background
background_tasks.add_task(
process_customer_inquiry,
phone_number,
text_body
)
return {"status": "received"}
except Exception as e:
return {"status": "error", "message": str(e)}
Processing the Inquiry
from openai import AsyncOpenClient
import re
openai_client = AsyncOpenClient()
async def extract_customer_requirements(message: str) -> dict:
"""Use AI to extract structured requirements from message"""
prompt = f"""
Extract the following from this customer inquiry:
- Product names/requirements
- Quantities
- Any specific features mentioned
Inquiry: "{message}"
Return as JSON with keys: products (list), quantities (dict), notes (string)
"""
response = await openai_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "You extract structured data from customer messages."},
{"role": "user", "content": prompt}
],
response_format={"type": "json_object"}
)
return json.loads(response.choices[0].message.content)
Searching the Product Catalog
from sqlalchemy import select
from your_models import Product
async def search_products(requirements: list[str]) -> list[Product]:
"""Search catalog for matching products"""
query = select(Product).where(
Product.name.ilike(f"%{requirements[0]}%")
)
result = await db.execute(query)
return result.scalars().all()
Generating the Quotation
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
import io
def generate_quotation_pdf(customer: str, products: list) -> bytes:
"""Generate PDF quotation"""
buffer = io.BytesIO()
pdf = canvas.Canvas(buffer, pagesize=letter)
# Header
pdf.setFont("Helvetica-Bold", 16)
pdf.drawString(100, 750, "SALES QUOTATION")
# Customer info
pdf.setFont("Helvetica", 12)
pdf.drawString(100, 720, f"Customer: {customer}")
# Products
y_position = 680
total = 0
for product in products:
line_total = product.price * product.quantity
total += line_total
pdf.drawString(100, y_position, f"{product.name} x {product.quantity}")
pdf.drawString(400, y_position, f"₹{line_total:.2f}")
y_position -= 30
# Total
pdf.setFont("Helvetica-Bold", 12)
pdf.drawString(100, y_position - 20, f"TOTAL: ₹{total:.2f}")
pdf.save()
buffer.seek(0)
return buffer.read()
Sending the Reply
async def send_whatsapp_message(
phone_number: str,
message: str,
pdf_url: str = None
):
"""Send message via WhatsApp Business API"""
url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages"
headers = {
"Authorization": f"Bearer {WHATSAPP_ACCESS_TOKEN}",
"Content-Type": "application/json"
}
data = {
"messaging_product": "whatsapp",
"to": phone_number,
"type": "text",
"text": {"body": message}
}
async with httpx.AsyncClient() as client:
if pdf_url:
# Send document
data["type"] = "document"
data["document"] = {
"link": pdf_url,
"caption": message
}
response = await client.post(url, headers=headers, json=data)
return response.json()
Putting It All Together
async def process_customer_inquiry(phone_number: str, message: str):
"""Complete workflow for handling customer inquiry"""
try:
# 1. Extract requirements with AI
requirements = await extract_customer_requirements(message)
# 2. Search catalog
products = await search_products(requirements["products"])
if not products:
await send_whatsapp_message(
phone_number,
"Sorry, I couldn't find matching products. Could you please provide more details?"
)
return
# 3. Calculate totals
total = sum(p.price * p.quantity for p in products)
# 4. Generate PDF
pdf_bytes = generate_quotation_pdf(phone_number, products)
# 5. Upload PDF (to S3, Cloudinary, etc.)
pdf_url = await upload_pdf_to_storage(pdf_bytes)
# 6. Send WhatsApp reply
summary = f"""
🎯 Your Quotation is Ready!
Products: {', '.join(p.name for p in products)}
Total: ₹{total:.2f}
PDF attached. Let me know if you need any changes!
"""
await send_whatsapp_message(phone_number, summary, pdf_url)
# 7. Log to CRM
await log_quotation_to_crm(phone_number, products, total)
except Exception as e:
logger.error(f"Error processing inquiry: {e}")
await send_whatsapp_message(
phone_number,
"Sorry, there was an error processing your request. Please try again."
)
Interactive Buttons for Quick Actions
WhatsApp Business API supports interactive buttons:
async def send_product_selection_menu(phone_number: str, products: list):
"""Send interactive menu for product selection"""
url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/messages"
# Build product options
options = [
{
"type": "reply",
"reply": {"id": f"prod_{p.id}", "title": p.name[:20]}
}
for p in products[:3] # Max 3 options
]
data = {
"messaging_product": "whatsapp",
"to": phone_number,
"type": "interactive",
"interactive": {
"type": "button",
"body": {"text": "Which product interests you?"},
"action": {"buttons": options}
}
}
async with httpx.AsyncClient() as client:
response = await client.post(url, headers=headers, json=data)
return response.json()
Handling Button Responses
@app.post("/webhook/whatsapp")
async def receive_message(request: Request):
data = await request.json()
message = data["entry"][0]["changes"][0]["value"]["messages"][0]
# Check if it's a button response
if message["type"] == "interactive":
response_id = message["interactive"]["list_reply"]["id"] # or button_reply
# Extract product ID
product_id = response_id.replace("prod_", "")
# Send quotation for selected product
await send_product_quotation(message["from"], product_id)
return {"status": "processed"}
Best Practices
1. Message Templates for Initiated Conversations
For outbound messages (you initiate), use pre-approved templates:
async def send_template_message(phone_number: str, template_name: str):
data = {
"messaging_product": "whatsapp",
"to": phone_number,
"type": "template",
"template": {
"name": template_name,
"language": {"code": "en"}
}
}
# Send...
2. Rate Limiting
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/webhook/whatsapp")
@limiter.limit("10/minute")
async def receive_message(...):
...
3. Handle WhatsApp Media Uploads
async def upload_media_to_whatsapp(file_path: str) -> str:
"""Upload media to WhatsApp servers"""
url = f"https://graph.facebook.com/v18.0/{PHONE_NUMBER_ID}/media"
async with httpx.AsyncClient() as client:
with open(file_path, "rb") as f:
files = {"file": f}
data = {
"messaging_product": "whatsapp",
"type": "pdf"
}
response = await client.post(
url,
headers={"Authorization": f"Bearer {WHATSAPP_ACCESS_TOKEN}"},
files=files,
data=data
)
return response.json()["id"] # Media ID for sending
Cost Considerations
WhatsApp Business API pricing varies:
- Free tier: 1,000 conversations/month (customer-initiated)
- Paid tiers: Based on conversation categories
For high volume (100+ daily), expect ~$0.005-$0.02 per conversation depending on region.
Results
After implementation:
- Quotation time: 5 min → < 1 min (5x faster)
- Error rate: Manual errors eliminated
- Customer satisfaction: Instant responses improved engagement
- Sales team productivity: Freed up 4+ hours daily
Conclusion
WhatsApp Business API integration transformed our sales workflow from a manual, error-prone process into an automated, efficient system. The key is combining messaging APIs with AI for natural language understanding and legacy system integration.
For businesses in regions where WhatsApp is the primary communication channel, this integration is a game-changer.
Have questions about WhatsApp API integration or want to share your experience? Let’s connect!