Type something to search...
Integrating WhatsApp Business API for Sales Automation

Integrating WhatsApp Business API for Sales Automation

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:

  1. Receive customer inquiry via WhatsApp/phone
  2. Open accounting software (legacy desktop application)
  3. Search products manually in the catalog
  4. Calculate totals in a spreadsheet or calculator
  5. Generate quotation PDF using accounting software
  6. Switch to WhatsApp manually to send the PDF
  7. 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:

  1. Customer sends inquiry via WhatsApp
  2. AI extracts requirements from the message
  3. System searches catalog automatically via API
  4. Quotation generates instantly
  5. 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:

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!

Related Posts

Building RAG Pipelines with pgvector and OpenAI: A Practical Guide

Building RAG Pipelines with pgvector and OpenAI: A Practical Guide

Retrieval-Augmented Generation (RAG) has become the go-to architecture for building AI applications that need to reason over custom data. After implementing RAG pipelines that achieved 99% accuracy in

Read More
Reducing Story Generation from 20 mins to 2 mins with Temporal.io

Reducing Story Generation from 20 mins to 2 mins with Temporal.io

When building an AI-powered personalized storybook platform, I faced a critical performance challenge: generating a single story took 20 minutes. After implementing Temporal.io for workflow orchestrat

Read More