{
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 18 "
}
]
},
"timezone": "Asia/Kolkata"
},
"name": "18th 9am IST",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [240, 300]
}0 9 18 reads as: minute 0, hour 9, day-of-month 18, every month, every day-of-week. The timezone field is mandatory — without it, the cron runs at 14:30 IST instead of 09:00.
### Node 2 — WhatsApp Cloud API send template with buttons
{
"parameters": {
"method": "POST",
"url": "https://graph.facebook.com/v21.0/{{ $env.WA_PHONE_ID }}/messages",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{ "name": "Authorization", "value": "Bearer {{ $env.WA_TOKEN }}" },
{ "name": "Content-Type", "value": "application/json" }
]
},
"sendBody": true,
"bodyContentType": "json",
"jsonBody": "={\n \"messaging_product\": \"whatsapp\",\n \"to\": \"{{ $json.phone }}\",\n \"type\": \"template\",\n \"template\": {\n \"name\": \"gstr3b_reminder_v2\",\n \"language\": { \"code\": \"en\" },\n \"components\": [\n {\n \"type\": \"body\",\n \"parameters\": [\n { \"type\": \"text\", \"text\": \"{{ $json.client_name }}\" },\n { \"type\": \"text\", \"text\": \"{{ $json.gstin }}\" },\n { \"type\": \"text\", \"text\": \"{{ $json.due_date }}\" }\n ]\n },\n {\n \"type\": \"button\",\n \"sub_type\": \"quick_reply\",\n \"index\": \"0\",\n \"parameters\": [\n { \"type\": \"payload\", \"payload\": \"READY_{{ $json.gstin }}\" }\n ]\n },\n {\n \"type\": \"button\",\n \"sub_type\": \"quick_reply\",\n \"index\": \"1\",\n \"parameters\": [\n { \"type\": \"payload\", \"payload\": \"EXTEND_{{ $json.gstin }}\" }\n ]\n },\n {\n \"type\": \"button\",\n \"sub_type\": \"quick_reply\",\n \"index\": \"2\",\n \"parameters\": [\n { \"type\": \"payload\", \"payload\": \"SKIP_{{ $json.gstin }}\" }\n ]\n }\n ]\n }\n}",
"options": { "timeout": 15000 }
},
"name": "Send GSTR-3B reminder",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [680, 300]
}READY_27ABCDE1234F1Z5). Our reply-handler workflow parses that payload and finds the client without ambiguity — even if two clients share a phone number (it happens with family-run businesses).
### Node 3 — Reply webhook handler (separate workflow)
{
"parameters": {
"httpMethod": "POST",
"path": "wa-reply",
"responseMode": "lastNode",
"options": {}
},
"name": "WA reply webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [240, 300],
"webhookId": "REDACTED"
}const body = $input.item.json.body;
const messages = body?.entry?.[0]?.changes?.[0]?.value?.messages || [];
if (messages.length === 0) return []; // status update, not a message
const msg = messages[0];
if (msg.type !== 'button') return [{ json: { skip: true, reason: 'not_a_button' } }];
const payload = msg.button.payload;
const [action, gstin] = payload.split('_');
if (!['READY', 'EXTEND', 'SKIP'].includes(action)) return [];
return [{
json: {
action,
gstin,
phone: msg.from,
timestamp: new Date(parseInt(msg.timestamp) * 1000).toISOString(),
message_id: msg.id
}
}];Name: gstr3b_reminder_v2
Category: Utility
Language: English
Body:
Hi {{1}},
GSTR-3B for {{2}} is due {{3}}.
Please confirm:
- READY: filing data ready, share via portal
- EXTEND: need extra time (we will reach out)
- SKIP: NIL return for this period
— [CA firm name] auto-reminder
Buttons:
[Quick reply] READY
[Quick reply] EXTEND
[Quick reply] SKIP- WhatsApp template still approved (Meta sometimes silently expires templates; check status weekly)
- Notion GSTR_clients database has zero stale rows (clients off-boarded marked inactive)
- All client phone numbers in E.164 format (+91 prefix, no spaces, no dashes)
- Reply webhook subscription confirmed working with a test button tap from your own phone
- Permanent system-user access token verified (not the 24-hour debug token that expires)
- Partner-incharge column populated for every client (chaser DMs need it)
- Notion replies database has the right schema (action, gstin, phone, replied_at)
- Error workflow set — failed sends should not block the rest of the loop
- Manual test send to a known phone scheduled for the 17th evening
- Backup notification path (email) for the 19th chaser if WhatsApp send fails
gstr3b_reminder_v2 after the v1 had a typo we fixed.
Symptom: "Client gets the message but the buttons are missing on iOS." Cause: iOS WhatsApp version below 23.10 has known button-rendering bugs. Fix: nothing you can do server-side. Most users are on current versions; for the few stragglers, the message body still works (READY / EXTEND / SKIP can be typed as plain text replies and parsed by a regex fallback).
Symptom: "Reply webhook fires but client name lookup returns nothing." Cause: phone number in Meta webhook is in different format from what we stored (e.g., 919876543210 vs +919876543210). Fix: normalise both ends to E.164 with explicit + sign. The reply handler should strip the + and prepend it consistently.
Symptom: "Same client received the reminder twice in 5 minutes." Cause: Meta retried the API call after a network blip and we did not idempotency-protect. Fix: add a message_id deduplication table — for each unique (client_phone, period) pair, only allow one send per day.
Symptom: "Partners complain the chaser DMs are too noisy." Cause: chaser fires 24 hours after the original send for any non-reply, including clients who replied via email outside the WhatsApp flow. Fix: add an "alternative_response" column to Notion that the partner can tick — chaser skips clients with that ticked.
Symptom: "WhatsApp limit of 1,000 unique users in 24 hours hit on month-end." Cause: tier-1 WhatsApp Business accounts have a 1,000-recipient daily cap. Fix: spread sends over 2 hours via the SplitInBatches node with a 5-second delay, or apply for tier-2 (10,000/day) once you have 1+ months of clean send history.
## The reply handler in detail
When a client taps READY, the webhook handler updates Notion in 3 steps:
1. Parse the payload (READY_27ABCDE1234F1Z5 → action=READY, gstin=27ABCDE1234F1Z5).
2. Query Notion GSTR_clients for the row with that gstin.
3. Update the GSTR_replies database with a new row: client (relation), period (current month), action, replied_at, message_id.
A separate Slack DM goes to the partner-incharge: "Pinky Textiles confirmed READY for Nov 2025 GSTR-3B at 09:14 IST." Partners report this single change has improved their internal tracking more than anything else they have tried.
For more on how we wire similar Notion + Slack patterns, see our [client-onboarding workflow](/blog/n8n-stripe-convertkit-slack-client-onboarding-workflow). The 22-node onboarding flow uses the same Notion + WhatsApp pattern with different triggers.
## Mini case study — 4-partner CA firm in Indore, 3 months live
The first install ran from October 18, 2025. Three monthly runs since. October numbers: 240 clients sent, 211 replies via button (88%), 17 EXTEND requests handled, 12 SKIP for NIL returns. November numbers: 240 sent, 217 replies (90%). December (today, 18th): 240 sent at 09:00, 152 replies in the first 4 hours. The two associates who used to spend the day on this now handle filing prep — one of them mentioned "I had time to read the GST council notification properly for the first time in two years."
For another high-volume Indian SMB workflow we built, see [the BFCM cart-recovery flows](/blog/bfcm-cart-recovery-n8n-flows-running-on-softechinfra-client-sites) — same WhatsApp Cloud API pattern with different triggers.
## When not to build this
Skip this if (a) your client list is under 50 — the build cost is hard to amortise against ~5 hours of associate time saved per month, (b) your clients are not on WhatsApp — for older or extremely traditional client bases, this fails entirely; SMS is a worse fallback because two-way SMS in India is expensive and slow, or (c) you have ongoing trust issues with clients who suspect "auto-messages" — sometimes a text from the partner's personal number is what wins. We turned down a Mumbai chartered firm in 2025 for reason (c) — their senior partners did not want the firm to look automated.
For more on the [AI automation services](/services/ai-automation) we offer to professional service firms, see the [Softechinfra services overview](/services/crm-development) for the full lineup.
## FAQ
### Do clients need to opt in to receive WhatsApp from the firm?
Yes, every recipient needs documented consent. We add a clause to the firm's engagement letter: "I consent to receiving filing reminders, document requests, and other transactional updates via WhatsApp at the registered mobile." The signed PDF lives in the client's Notion row.
### What happens if a client replies with free text instead of a button?
The reply still arrives at the webhook. A fallback Code node looks for keywords (READY, EXTEND, SKIP, ready, "kar diya", "ho gaya") and tries to match. If no match, the message is forwarded to the partner-incharge via Slack with the raw text — they handle it manually.
### How does the firm bill clients for SKIP/NIL returns?
Separately. The SKIP button just changes the workflow downstream — no filing data requested, just a one-line Notion entry. The firm's own billing system (we have not touched that) handles the NIL filing fee.
### What if a client wants to switch off these reminders?
A "active" boolean column in the Notion GSTR_clients database. Set to false → client skipped on the next month's send. We also support a STOP keyword in the reply handler that auto-unsubscribes for 90 days.
### Does this work for GSTR-1 too?
Yes, by changing the cron to day 11 (GSTR-1 due date is the 11th for monthly filers). The same template structure works — just rename to gstr1_reminder_v1. We have shipped the GSTR-1 variant for two firms.
### How does the firm handle TDS / TCS reminders?
The same pattern, different cron (7th of each month for TDS). We are building a unified "compliance_reminder" workflow that reads a master Notion calendar and fires the right template per due date. Should ship in Q1 2026.
### What about client GSTIN changes (mergers, demergers)?
The Notion row is the source of truth. The CA firm's account manager updates the GSTIN there; the next month's send picks up the new value. We log GSTIN history in a separate "client_history" Notion database for audit.
Want this GSTR reminder system built for your CA practice?
We ship the full 19-node flow — n8n on your infra, Meta Business + Notion setup, WhatsApp template approval, partner training — in 7 working days for ₹68,000. Suitable for any CA or compliance firm with 50+ active clients on monthly GST cycles.
Book a 20-min Call
