# WhatsApp Automation for Small Businesses in 2026: AI Replies, Lead Capture & Tiered Commissions

> Source: <https://dev.to/hayrullahkar/whatsapp-automation-for-small-businesses-in-2026-ai-replies-lead-capture-tiered-commissions-4b89>
> Published: 2026-07-16 21:44:58+00:00

Your customers would rather message you on WhatsApp than fill in a contact form. That's fine at ten conversations a day. At a hundred, messages get missed, nobody knows which rep is on which deal, and at month-end somebody rebuilds the commission sheet by hand and gets it wrong.

The usual answer is a $49–$499/month WhatsApp SaaS platform, priced per seat, with your customer data living in someone else's database. This post is the other answer: the same workflow on Google Sheets + Apps Script — and the one piece I see teams get wrong every single time, with the code to fix it.

It isn't the messaging. Wiring a WhatsApp webhook into a sheet is a couple of hours of work, and I've written that build up separately — the webhook, the AI reply, and the lock that stops two reps chasing the same lead are all in [Build a WhatsApp Sales Inbox in Google Sheets](https://magesheet.com/blog/automating-whatsapp-sales-google-sheets). I won't repeat it here.

The part that breaks is **the commission math**. Someone writes `=IF(revenue>10000, revenue*0.08, revenue*0.05)`

into a column, and three things kill it:

So that's what this post builds: a tiered commission engine that survives rule changes and refunds.

This is the whole trick. Make a `Commission Rules`

tab, one row per rule:

```
rule_id | rep_id   | effective_from | effective_to | tier_1_cap | tier_1_pct |
        |          |                |              | tier_2_cap | tier_2_pct | tier_3_pct
--------+----------+----------------+--------------+------------+------------+-----------
R1      | ALL      | 2026-01-01     |              | 10000      | 0.05       |
        |          |                |              | 50000      | 0.08       | 0.10
R2      | rep_ayse | 2026-06-01     |              | 10000      | 0.06       |
        |          |                |              | 50000      | 0.09       | 0.12
```

`rep_id`

is either a specific rep or `ALL`

(the house default). Percentages are decimals — `0.05`

is 5%. When the plan changes, you close the old rule with an `effective_to`

date and add a new row. History keeps calculating at the rate that was live on the day of the sale.

``` js
function findRule(rules, repId, saleDate) {
  const d = new Date(saleDate);
  const matches = rules.filter(r =>
    (r.rep_id === repId || r.rep_id === 'ALL') &&
    d >= new Date(r.effective_from) &&
    (!r.effective_to || d <= new Date(r.effective_to))
  );
  // A rule written for this rep always beats the "ALL" fallback.
  matches.sort((a, b) => (a.rep_id === 'ALL' ? 1 : 0) - (b.rep_id === 'ALL' ? 1 : 0));
  return matches[0] || null;
}
```

Here's the bug in every hand-written commission column. A rep has booked $45,000 this quarter and closes another $10,000. Tier 2 ends at $50,000. So $5,000 of that sale earns 8% and $5,000 earns 10% — not $10,000 at one rate.

```
// Commission for ONE sale, given how much the rep already booked this period.
// A single sale can span two or three tiers — that's what formulas get wrong.
function commissionForSale(bookedBefore, amount, rule) {
  const bands = [
    { upTo: Number(rule.tier_1_cap), pct: Number(rule.tier_1_pct) },
    { upTo: Number(rule.tier_2_cap), pct: Number(rule.tier_2_pct) },
    { upTo: Infinity,                pct: Number(rule.tier_3_pct) },
  ];
  let from = bookedBefore, left = amount, commission = 0;

  for (const band of bands) {
    if (left <= 0) break;
    const room = Math.max(band.upTo - from, 0);
    const take = Math.min(left, room);
    commission += take * band.pct;
    from += take;
    left -= take;
  }
  return commission;
}
```

With the `R1`

rule above: `commissionForSale(45000, 10000, R1)`

returns `900`

— $5,000 at 8% plus $5,000 at 10%. The naive formula returns either $800 or $1,000, and your rep notices.

Never edit or delete the original row. A refund is its own row with a negative `amount`

and a `reverses_transaction_id`

pointing back at the sale. Then the engine reverses exactly the commission that sale earned — not a recalculated guess.

``` js
function runCommissions(transactions, rules) {
  const sorted = transactions.slice()
    .sort((a, b) => new Date(a.date) - new Date(b.date));
  const booked = {};   // rep_id -> revenue booked so far
  const earned = {};   // transaction_id -> commission it earned
  const out = [];

  sorted.forEach(t => {
    if (t.reverses_transaction_id) {                    // refund row
      const original = earned[t.reverses_transaction_id] || 0;
      booked[t.rep_id] = (booked[t.rep_id] || 0) + Number(t.amount);  // negative
      out.push({ id: t.transaction_id, rep: t.rep_id, commission: -original });
      return;
    }
    const rule = findRule(rules, t.rep_id, t.date);
    if (!rule) {
      out.push({ id: t.transaction_id, rep: t.rep_id, commission: 0, note: 'no rule' });
      return;
    }
    const before = booked[t.rep_id] || 0;
    const c = commissionForSale(before, Number(t.amount), rule);
    booked[t.rep_id] = before + Number(t.amount);
    earned[t.transaction_id] = c;
    out.push({ id: t.transaction_id, rep: t.rep_id, commission: c });
  });
  return out;
}
```

Because it walks transactions in date order and keeps a running total per rep, the tier boundaries land where they actually landed in real life. I unit-tested this before shipping it — the cases that matter are a sale spanning all three tiers, a rule that isn't effective yet falling back to `ALL`

, and a refund netting to exactly zero.

At small-business volume, the running cost is LLM tokens plus Meta's conversation fees — roughly $0.005–$0.08 per conversation depending on category and country, which for most SMBs lands near $50/month all-in. Compare that to $49–$499/month per platform, plus per-seat fees. The bigger difference isn't the invoice, though: the sheet is yours, and so is the commission logic.

WhatsApp's often-quoted ~98% open rate is a vendor benchmark rather than a controlled study — but you don't need the exact number to know the channel outperforms email for a reply-now conversation.

`reverses_transaction_id`

.The messaging half of WhatsApp automation is easy and well covered. The commission half is where teams quietly lose money and trust — and it's solved by two ideas: keep the tiers in a dated rules table, and split each sale across the bands it actually crosses.

The production version — multi-agent splits, clawback windows, and the payout approval flow — is written up on the [MageSheet blog](https://magesheet.com/blog/whatsapp-automation-small-businesses-2026).

Built by the MageSheet team.
