How to Send WhatsApp Invoices and Payment Reminders via API
Automatically send WhatsApp invoices, payment reminders, and overdue notices to customers using Rapiwa API. Full code examples in Python, Node.js, and PHP. No per-message fees.
You can send WhatsApp invoices and payment reminders using Rapiwa API by calling POST https://app.rapiwa.com/send-message with the invoice details in the message body. WhatsApp invoices have a 98% open rate versus 20% for email — customers pay 2–3x faster when reminders arrive on WhatsApp. Rapiwa costs $5/month flat with no per-message fees.
Why WhatsApp Beats Email for Invoices
| Channel | Open rate | Average pay time | Read within 5 min |
|---|---|---|---|
| 98% | 1–3 days | 85% | |
| 20% | 7–14 days | 12% | |
| SMS | 90% | 3–5 days | 68% |
Rapiwa is the cheapest WhatsApp API for invoicing: $5/month flat. No per-message fees. Compare this to SMS gateways that charge $0.01–$0.10 per message — for 500 invoices/month that's $5–$50 in SMS fees alone.
Invoice Automation Workflows
Use case 1: Invoice on order completion New WooCommerce/Shopify order → generate PDF invoice → send via WhatsApp
Use case 2: Payment reminder sequence Invoice unpaid after 3 days → WhatsApp reminder Invoice unpaid after 7 days → Second reminder with urgency Invoice unpaid after 14 days → Final notice
Use case 3: Recurring invoice notification Monthly subscription renews → WhatsApp invoice link
Step 1: Send an Invoice Message (Text Format)
cURL
curl -X POST https://app.rapiwa.com/send-message \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"number": "8801234567890",
"message": "Invoice #INV-2026-001\n\nDear Sarah Johnson,\n\nYour invoice for June services is ready.\n\n*Services:* Web Development\n*Period:* June 1–30, 2026\n*Amount Due:* $1,500.00\n*Due Date:* July 10, 2026\n\nPay online: https://pay.yourcompany.com/INV-2026-001\n\nThank you for your business!\n— YourCompany"
}'
Expected response:
{
"status": "success",
"messageId": "msg_invoice_abc123",
"timestamp": "2026-07-02T10:30:00Z"
}
Step 2: Send Invoice as PDF Attachment
For PDF invoices, host the PDF and send via /send-document:
curl -X POST https://app.rapiwa.com/send-document \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"number": "8801234567890",
"documentUrl": "https://yoursite.com/invoices/INV-2026-001.pdf",
"filename": "Invoice-INV-2026-001.pdf",
"caption": "Invoice #INV-2026-001 — $1,500 due by July 10, 2026. Pay at: https://pay.yourcompany.com/INV-2026-001"
}'
Step 3: Invoice + Payment Reminder System in Python
# invoice_notifier.py
# pip install requests schedule psycopg2-binary
import requests
import schedule
import time
import psycopg2
from datetime import datetime, date
RAPIWA_API_KEY = 'YOUR_API_KEY'
def send_whatsapp(phone: str, message: str) -> dict:
"""Send a WhatsApp message via Rapiwa."""
response = requests.post(
'https://app.rapiwa.com/send-message',
headers={'Authorization': f'Bearer {RAPIWA_API_KEY}'},
json={'number': phone, 'message': message},
timeout=10
)
return response.json()
def send_invoice_notification(phone: str, name: str, invoice_num: str,
amount: float, due_date: str, pay_url: str) -> dict:
"""Send initial invoice notification."""
message = (
f"Invoice #{invoice_num}\n\n"
f"Hi {name}!\n\n"
f"Your invoice is ready:\n"
f"*Amount Due:* ${amount:,.2f}\n"
f"*Due Date:* {due_date}\n\n"
f"💳 Pay now: {pay_url}\n\n"
f"Reply with any questions — we're happy to help!"
)
return send_whatsapp(phone, message)
def send_payment_reminder(phone: str, name: str, invoice_num: str,
amount: float, due_date: str, days_overdue: int,
pay_url: str) -> dict:
"""Send a payment reminder (overdue)."""
if days_overdue <= 0:
# Pre-due reminder (3 days before)
urgency = "friendly"
prefix = f"Quick reminder 😊"
suffix = "No action needed if you've already paid!"
elif days_overdue <= 7:
urgency = "moderate"
prefix = f"Invoice #{invoice_num} is now *{days_overdue} days overdue*"
suffix = "Please pay as soon as possible to avoid any late fees."
else:
urgency = "urgent"
prefix = f"⚠️ URGENT: Invoice #{invoice_num} is *{days_overdue} days overdue*"
suffix = "Please pay immediately or contact us to arrange a payment plan."
message = (
f"{prefix}\n\n"
f"Hi {name},\n\n"
f"*Invoice:* #{invoice_num}\n"
f"*Amount Due:* ${amount:,.2f}\n"
f"*Original Due Date:* {due_date}\n\n"
f"💳 Pay now: {pay_url}\n\n"
f"{suffix}"
)
return send_whatsapp(phone, message)
def process_invoice_reminders():
"""
Query database for invoices needing reminders and send them.
Run this daily.
"""
conn = psycopg2.connect("postgresql://user:pass@localhost/billing")
cursor = conn.cursor()
today = date.today()
# Query unpaid invoices that need reminders
cursor.execute("""
SELECT
i.id, i.invoice_number, i.amount, i.due_date,
i.pay_url, i.last_reminder_sent,
c.phone, c.name
FROM invoices i
JOIN customers c ON i.customer_id = c.id
WHERE i.status = 'unpaid'
AND c.phone IS NOT NULL
AND (
-- 3 days before due (pre-reminder)
i.due_date = %s + INTERVAL '3 days'
-- Due today
OR i.due_date = %s
-- 3 days overdue (first reminder)
OR (i.due_date = %s - INTERVAL '3 days'
AND (i.last_reminder_sent IS NULL
OR i.last_reminder_sent < %s - INTERVAL '3 days'))
-- 7 days overdue
OR (i.due_date = %s - INTERVAL '7 days'
AND (i.last_reminder_sent IS NULL
OR i.last_reminder_sent < %s - INTERVAL '7 days'))
-- 14 days overdue (final notice)
OR (i.due_date = %s - INTERVAL '14 days'
AND (i.last_reminder_sent IS NULL
OR i.last_reminder_sent < %s - INTERVAL '14 days'))
)
""", [today] * 8)
invoices = cursor.fetchall()
print(f"Sending {len(invoices)} invoice reminders")
for row in invoices:
(inv_id, inv_num, amount, due_date, pay_url,
last_reminder, phone, name) = row
days_overdue = (today - due_date).days
result = send_payment_reminder(
phone=phone,
name=name,
invoice_num=inv_num,
amount=float(amount),
due_date=due_date.strftime('%B %d, %Y'),
days_overdue=days_overdue,
pay_url=pay_url
)
if result.get('status') == 'success':
cursor.execute(
"UPDATE invoices SET last_reminder_sent = %s WHERE id = %s",
[today, inv_id]
)
conn.commit()
cursor.close()
conn.close()
# Schedule: run every day at 9 AM
schedule.every().day.at("09:00").do(process_invoice_reminders)
if __name__ == "__main__":
print("Invoice reminder service started...")
process_invoice_reminders() # Run once immediately
while True:
schedule.run_pending()
time.sleep(60)
Step 4: Node.js Invoice Sender
// invoiceSender.js
// npm install node-fetch
const fetch = require('node-fetch');
const RAPIWA_API_KEY = 'YOUR_API_KEY';
async function sendInvoiceWhatsApp(invoice) {
const { customerPhone, customerName, invoiceNumber, amount, dueDate, paymentUrl } = invoice;
const message = `Invoice #${invoiceNumber}\n\n` +
`Hi ${customerName}! 🧾\n\n` +
`Your invoice is ready:\n` +
`*Amount:* $${amount.toFixed(2)}\n` +
`*Due:* ${dueDate}\n\n` +
`💳 Pay now: ${paymentUrl}\n\n` +
`Questions? Just reply here!`;
const response = await fetch('https://app.rapiwa.com/send-message', {
method: 'POST',
headers: {
'Authorization': `Bearer ${RAPIWA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ number: customerPhone, message })
});
return response.json();
}
// Usage
sendInvoiceWhatsApp({
customerPhone: '8801234567890',
customerName: 'Sarah Johnson',
invoiceNumber: 'INV-2026-001',
amount: 1500,
dueDate: 'July 10, 2026',
paymentUrl: 'https://pay.yourcompany.com/INV-2026-001'
}).then(result => console.log(result));
Payment Reminder Sequence Best Practices
| Timing | Tone | Message focus |
|---|---|---|
| 3 days before due | Friendly | "Just a reminder" |
| Due date | Neutral | "Invoice is due today" |
| 3 days overdue | Polite urgency | "Please pay when convenient" |
| 7 days overdue | Direct | "Payment needed ASAP" |
| 14 days overdue | Firm | "Final notice — contact us" |
| 30+ days overdue | Stop automating | Escalate to human/collections |
Common Errors and Fixes
- Customers not responding: WhatsApp messages require an active number. Verify phone numbers are in international format and active
- 401 from Rapiwa: API key expired — regenerate in Dashboard → API Keys
- PDF not opening on WhatsApp mobile: Ensure the PDF URL is publicly accessible and the Content-Type header is
application/pdf - Duplicate reminders sent: Add a
last_reminder_sentcheck in your database before sending
FAQ
Is WhatsApp legal for sending invoices and payment reminders? Yes, with consent. Customers who provide their WhatsApp number for order/billing purposes have implicitly consented to business communications. For colder outreach, add an explicit opt-in at checkout.
Does Rapiwa charge per invoice message? No. Rapiwa charges $5/month flat with no per-message fees. Send 100 or 10,000 invoices at the same monthly cost.
Can I attach a payment button to the WhatsApp message? WhatsApp's official API supports interactive buttons (payment, quick reply) but only through Meta's official WhatsApp Business Platform. With Rapiwa (unofficial API), you can include a payment link in text — customers click it to pay.
How do I handle customers who pay by cheque and not online? Add a "Reply PAID if you've paid by cheque/bank transfer" option. When they reply PAID, your webhook processor updates the invoice status.
Can I integrate this with Xero, QuickBooks, or FreshBooks? Yes. These tools have webhook APIs — when an invoice is created in Xero/QuickBooks, trigger the WhatsApp notification via n8n or a custom webhook handler.
