DEV Community

Subhendu Das
Subhendu Das

Posted on

Send Contracts via WhatsApp with DoAide Contract Generator

Problem

Indian SMB owners, freelancers, and startups often need to share newly generated contracts—NDAs, employment contracts, service agreements—quickly with clients or partners. Sending a PDF by email or uploading it to a cloud folder adds friction and delays the signing process. This is where contract generator pays off in practice.

How the Feature Works

DoAide Contracts adds a single‑click WhatsApp share button after a contract is generated. The flow is:

  1. Generate: The user selects a template (e.g., employment contract template) and fills in the form.
  2. Store: FastAPI saves the contract as a PDF blob in PostgreSQL and returns a contract ID.
  3. Share: The React UI renders a Share via WhatsApp button. When clicked, it calls a FastAPI endpoint that streams the PDF to the WhatsApp Business API.
  4. Confirm: A toast informs the user that the contract was sent.

The user never leaves the site; the contract is delivered instantly to the chosen WhatsApp contact. Getting contract generator right early saves rework later.

Frontend Implementation

The share button lives in components/ShareWhatsAppButton.jsx:

import { useState } from "react";

export default function ShareWhatsAppButton({ contractId, recipient }) {
  const [sending, setSending] = useState(false);

  const send = async () => {
    setSending(true);
    try {
      const res = await fetch(`/api/contract/${contractId}/send-whatsapp`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ phone: recipient }),
      });
      if (!res.ok) throw new Error("Send failed");
      alert("Contract sent to WhatsApp");
    } catch (e) {
      alert("Could not send contract");
    } finally {
      setSending(false);
    }
  };

  return (
    <button onClick={send} disabled={sending} className="btn-whatsapp">
      {sending ? "Sending…" : "Share via WhatsApp"}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

The component uses a simple POST request; the button is styled with the teal theme introduced in the latest branding update.

Backend Implementation

FastAPI exposes the endpoint in api/contract.py:

from fastapi import APIRouter, HTTPException
from sqlalchemy.orm import Session
from .models import Contract
from .whatsapp import send_pdf_via_whatsapp

router = APIRouter()

@router.post("/contract/{contract_id}/send-whatsapp")
async def send_whatsapp(contract_id: int, payload: dict, db: Session):
    contract = db.query(Contract).filter(Contract.id == contract_id).first()
    if not contract:
        raise HTTPException(status_code=404, detail="Contract not found")

    phone = payload.get("phone")
    if not phone:
        raise HTTPException(status_code=400, detail="Phone number required")

    # contract.pdf is a byte array stored in PostgreSQL
    success = await send_pdf_via_whatsapp(phone, contract.pdf, contract.title)
    if not success:
        raise HTTPException(status_code=500, detail="WhatsApp send failed")

    return {"status": "sent"}
Enter fullscreen mode Exit fullscreen mode

The helper send_pdf_via_whatsapp wraps the Twilio WhatsApp API:

import aiohttp

async def send_pdf_via_whatsapp(to: str, pdf_bytes: bytes, title: str) -> bool:
    url = "https://api.twilio.com/2010-04-01/Accounts/ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Messages.json"
    data = {
        "From": "whatsapp:+14155238886",
        "To": f"whatsapp:{to}",
        "Body": f"Here is your {title}.",
    }
    files = {"MediaUrl": ("contract.pdf", pdf_bytes, "application/pdf")}
    auth = aiohttp.BasicAuth("ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "your_auth_token")
    async with aiohttp.ClientSession(auth=auth) as session:
        async with session.post(url, data=data, files=files) as resp:
            return resp.status == 201
Enter fullscreen mode Exit fullscreen mode

The PDF is streamed directly; no temporary file is written to disk. Good contract generator keeps the rest of the workflow predictable.

UX Considerations

  • The Share via WhatsApp button appears only after the contract is ready, keeping the interface clean.
  • The button uses a 48 px touch target, satisfying the mobile improvements commit.
  • On success, the toast uses the Inter font, aligning with the unified DoAide branding.

Benefits for Indian SMBs

  • Instant delivery: No email attachments, no manual uploads.
  • Higher conversion: Clients receive the contract in their primary messaging app.
  • Compliance: The contract remains a single PDF file, preserving formatting for legal review.

Conclusion

By integrating WhatsApp sharing into the contract generation workflow, DoAide Contracts removes a common bottleneck for Indian SMB owners. The implementation demonstrates how a lightweight FastAPI endpoint and a React button can leverage an external API to deliver a seamless user experience.

Further Reading

  • The project’s blog now contains a post on WhatsApp contract sharing.
  • The new SEO‑friendly blog posts include structured data for better discoverability.

Code Repository

All changes are available in the latest commit on GitHub: https://github.com/r2st/DoAide-Contracts/commit/9778d074b8bea1329eaed78e12438e9b496de2ed

Related reading

Top comments (0)