---
title: >-
  Cut cost per call in Kenya: call deflection vs callback economics (with the
  KES math)
description: >-
  Build the economic model for call deflection and callback scheduling using
  Sautikit, grounded in Kenyan labour and telecoms costs.
summary: >-
  Every inbound call that reaches a human agent costs money. This post builds
  the deflection vs callback economic model with Kenyan agent costs and Sautikit
  KES per-minute rates.
date: 2026-07-03T00:00:00.000Z
type: blog
---


## Summary

Every inbound call that reaches a human agent costs your business money. In Kenya, a Nairobi call-centre agent handling 40 calls/day at KES 50 000/month costs KES 31.25 per resolved call. The question is not whether to deflect calls but which ones to deflect, which to accelerate, and where the crossover point lies. This post builds the economic model for call deflection and callback scheduling using Sautikit's inbound voice flow, with numbers grounded in Kenyan labour and telecoms costs.

## The Economics of an Inbound Call: Fully Loaded Cost in KES

Most call centres underestimate per-call cost by counting only salary and ignoring NSSF, NHIF, office, equipment, and management allocation. A Nairobi agent earning KES 50 000/month has a fully-loaded cost closer to KES 75 000/month. At 40 calls/day and 22 working days:

```
cost_per_handled_call = 75 000 / (40 × 22) = KES 85.23
```

Inbound calls are free (KES 0/min), so a 2-minute IVR self-service call costs KES 0.

**Deflection value per call = KES 85 − KES 0 = KES 85**

At 200 calls/day with a 60% deflection rate: 120 calls/day × KES 85 = KES 10 200/day or KES 224 400/month saved.

## Call Deflection: IVR Self-Service for Tier-0 Queries

Not all calls can be deflected. The deflectability of a query depends on whether it can be resolved with information the system already has (balance, order status, appointment time) versus whether it requires human judgment or negotiation.

### Deflectability Scoring Rubric

| Query type | Deflectable? | IVR resolution rate | Notes |
|---|---|---|---|
| Account balance inquiry | Yes | >95% | Simple data lookup |
| Order status | Yes | >90% | Requires order ID lookup |
| Payment confirmation | Yes | >85% | Play back last transaction |
| Appointment time | Yes | >90% | Requires booking lookup |
| Password reset | Partial | ~60% | Often needs fallback |
| Loan dispute | No | &lt;20% | Requires human judgment |
| Fraud report | No | &lt;10% | Always escalate immediately |
| Complaint escalation | No | &lt;5% | Deflection destroys NPS |

The IVR self-service patterns that work are those with a structured answer. "Your balance is KES 1 250" can be automated. "Why was my loan declined" cannot.

### The Three-Level IVR with Callback Fallback

<!-- diagram omitted -->

```json
{
  "actions": [
    {
      "say": {
        "text": "Welcome. For account balance, press 1. For order status, press 2. For payment history, press 3. To speak to an agent, press 0.",
        "language": "en-KE"
      }
    },
    {
      "getDigits": {
        "numDigits": 1,
        "timeout": 10000,
        "finishOnKey": "",
        "action": "https://your-server.example.com/webhooks/ivr-main"
      }
    }
  ]
}
```

The main menu webhook branches on the digit received:

```javascript
// POST /webhooks/ivr-main
app.post("/webhooks/ivr-main", async (req, res) => {
  const { digits, sessionId } = req.body;

  switch (digits) {
    case "1":
      return res.json(await buildBalanceFlow(sessionId));
    case "2":
      return res.json(await buildOrderStatusFlow(sessionId));
    case "3":
      return res.json(await buildPaymentHistoryFlow(sessionId));
    case "0":
      return res.json(buildAgentTransfer());
    default:
      // No input: route to callback offer
      return res.json(buildCallbackOffer(sessionId));
  }
});
```

The callback offer for customers who press 0 or don't respond:

```javascript
function buildCallbackOffer(sessionId) {
  return {
    actions: [
      {
        say: {
          text: "All our agents are currently busy. Press 1 to receive a callback within 30 minutes. Press 2 to leave a voice message.",
          language: "en-KE",
        },
      },
      {
        getDigits: {
          numDigits: 1,
          timeout: 8000,
          finishOnKey: "",
          action: "https://your-server.example.com/webhooks/ivr-callback-choice",
        },
      },
    ],
  };
}
```

## What Can and Cannot Be Deflected Without Destroying NPS

The critical principle is **knowing when to stop deflecting.** Forcing a customer through IVR levels when they need an agent destroys NPS.

Two observable signals of "false self-service" (calls that appear deflected but are not resolved):

1. **The customer presses 0 (agent) at every menu level.** This customer was never going to accept IVR service. They should have been routed to an agent at the first press-0 signal.
2. **The customer hangs up during IVR.** The call is counted as "deflected" but the query is unresolved. The customer will call back or complain.

### Measuring False Self-Service with Sautikit CDRs

Sautikit's call detail records include the `digits` collected at each `GetDigits` step in the call's event log. By logging DTMF selections and correlating them with post-call outcomes, you can identify which IVR branches are "false self-service":

```sql
-- Calls where the customer pressed 0 at the main menu (agent request)
-- but the call still ended without an agent transfer (likely abandoned)
SELECT
    date_trunc('week', c.created_at)        AS week,
    COUNT(*)                                  AS total_calls,
    SUM(CASE WHEN ce.digits = '0'
             AND c.status = 'completed'
             AND c.duration_seconds < 60
             THEN 1 ELSE 0 END)              AS probable_false_deflections,
    ROUND(
        SUM(CASE WHEN ce.digits = '0'
                 AND c.status = 'completed'
                 AND c.duration_seconds < 60
                 THEN 1 ELSE 0 END)::numeric
        / NULLIF(COUNT(*), 0) * 100, 1
    )                                         AS false_deflection_rate_pct
FROM calls c
LEFT JOIN call_events ce
    ON ce.call_id = c.id
    AND ce.event_type = 'getDigits.completed'
    AND ce.menu_level = 1
WHERE c.direction = 'inbound'
  AND c.created_at >= NOW() - INTERVAL '30 days'
GROUP BY 1
ORDER BY 1 DESC;
```

IVR branches where the false-deflection rate exceeds 20% should be redesigned: either the content is unclear, the resolution path is too long, or the query type is genuinely not deflectable.

## Callback Scheduling: Turning Abandons into Recoverable Revenue

Call abandonment (callers who hang up before reaching an agent or completing the IVR) is a direct revenue leak. A caller who abandons has expressed intent. Recovering them with a callback converts that intent into a transaction.

The economics of callback recovery:

```
abandon_rate              = 15%  (typical Kenyan contact centre)
calls_per_day             = 200
abandoned_calls_per_day   = 200 × 0.15 = 30
avg_order_value           = KES 150  (per resolved call)
revenue_at_risk_per_day   = 30 × KES 150 = KES 4 500

callback_recovery_rate    = 60%  (industry benchmark)
recovered_calls_per_day   = 30 × 0.60 = 18
recovered_revenue_per_day = 18 × KES 150 = KES 2 700
```

A callback system recovering 60% of abandons saves KES 2 700/day in revenue that would otherwise be lost. The cost of the callback calls:

```
callback_calls_per_day    = 30  (one attempt per abandoned caller)
avg_callback_duration     = 3 min
cost_per_callback         = 3 × KES 3 = KES 9
daily_callback_cost       = 30 × KES 9 = KES 270
```

Net daily revenue improvement from callbacks: KES 2 700 − KES 270 = KES 2 430.

Payback period for building a callback system (assuming 5 days of engineering at KES 50 000/day):

```
build_cost     = 5 × KES 50 000 = KES 250 000
daily_benefit  = KES 2 340
payback_days   = 250 000 / 2 340 ≈ 107 days (≈ 3.5 months)
```

This is a defensible investment for any operation with more than 200 inbound calls/day.

## Implementation: the Callback via Voice Message (`Record` + Async Queue)

The most robust callback pattern uses `Record` (leave a voice message) combined with an async callback queue. The customer hangs up knowing they will be called back; the agent calls back with context from the voice message.

```json
{
  "actions": [
    {
      "say": {
        "text": "All our agents are busy. Please leave a message after the tone and we will call you back within 30 minutes.",
        "language": "en-KE"
      }
    },
    {
      "record": {
        "maxLength": 60,
        "finishOnKey": "#",
        "action": "https://your-server.example.com/webhooks/voicemail-received",
        "transcribe": false
      }
    }
  ]
}
```

The `voicemail-received` webhook puts a callback task in a queue:

```javascript
// POST /webhooks/voicemail-received
app.post("/webhooks/voicemail-received", async (req, res) => {
  const { callId, recordingUrl, from, duration } = req.body;

  await callbackQueue.add("callback", {
    callerNumber: from,
    recordingUrl,
    recordingDuration: duration,
    scheduledFor: Date.now() + 30 * 60 * 1000, // 30 minutes
    priority: "normal",
  });

  res.json({
    actions: [
      {
        say: {
          text: "Thank you. An agent will call you back within 30 minutes. Goodbye.",
          language: "en-KE",
        },
      },
      { hangup: {} },
    ],
  });
});
```

## Measuring Success: the Metrics That Matter

Three metrics determine whether your deflection and callback investment is working:

| Metric | Target | How to measure |
|---|---|---|
| Self-service resolution rate | >75% for deflectable queries | Calls that complete IVR without pressing 0 |
| False deflection rate | &lt;15% per branch | Presses-0 + sub-60s completions (SQL above) |
| Callback recovery rate | >50% | Callbacks that result in a resolved outcome |

The self-service resolution rate is the primary metric. If it is below 60%, the IVR content or routing logic needs redesign before investing in additional automation.

The false deflection rate per branch tells you where to focus redesign effort. A branch with a 35% false deflection rate is costing you NPS points without reducing agent load; it is the worst of both worlds.

Callback recovery rate below 40% usually means callbacks are being placed too late (more than 1 hour after the abandon) or to numbers that have since changed (dual-SIM switching; see [dual-SIM voice app patterns](/blog/dual-sim-voice-apps-kenya)).

Deflection routes tier-0 queries to self-service and callbacks recover abandons, but the hardest tickets still need a person plus context across channels. When a caller needs to move from voice to SMS, WhatsApp, or a human-agent desk with ticketing, [Helloduty](https://helloduty.com) handles that multi-channel handoff on top of your Sautikit voice flows.

## Get started

1. [Create a Sautikit workspace](/) and claim a phone number.
2. Top up over **M-Pesa**: KES billing, no card.
3. Ship the `Record` + async callback queue pattern above, then layer in the three-level IVR to start deflecting tier-0 queries.

**[Start with Sautikit →](/)** &nbsp;·&nbsp; **[See pricing →](/pricing)** &nbsp;·&nbsp; **[Need SMS, WhatsApp & an agent desk? Helloduty →](https://helloduty.com)**

## Getting Started

The [voice actions reference](/developers/concepts/voice-actions) covers `GetDigits`, `Say`, `Record`, and `Redirect`, the four verbs used in all IVR and callback patterns above. The [wallet concept page](/developers/concepts/wallet) covers the low-balance alert that prevents service interruptions during high-call-volume periods. Full per-minute pricing for inbound and outbound calls is at [/pricing](/pricing).

For operations currently running a manual callback process, the minimum viable implementation is the `Record` + async queue pattern above, roughly 2 days of engineering. The full three-level IVR with branching and CDR analysis takes approximately a week to build and tune, but the economic case at 200+ calls/day closes in under 4 months.
