G-SMS.

G-SMS · Use case

Appointment reminders by SMS in Cameroon

A booked slot that nobody shows up for cannot be recovered: it is simply lost. Here is how to send a reminder the day before from a scheduled job, what it costs per appointment, and the one limitation to know before you write the message.

The problem: the appointment is booked, then forgotten

In a dental practice, a garage or a training centre, appointments are usually made face to face or over the phone, sometimes weeks ahead, and written into a diary that notifies nobody. Between booking and the date itself, nothing reminds the customer that they reserved a slot.

Calling people one by one does not scale: phoning fifty patients the day before takes up half a day at the front desk, and half of those calls reach voicemail.

What a no-show costs

Use your own figures from last month rather than an average found elsewhere: count the booked slots that stayed empty. On 200 monthly appointments, thirty no-shows represent XAF 300,000 of revenue that never arrived, at XAF 10,000 a slot — for a practitioner who was present and paid all the same.

An empty slot costs twice: the revenue lost, and the next customer who could have taken it had they known a place was free.

The solution in three steps

1. Settle on the timing, once

The day before, late afternoon: the customer still has time to cancel, and you still have time to offer the slot to someone else. A second reminder two hours ahead makes sense for long or expensive appointments; past two messages a reminder turns into a nuisance and is ignored.

A reminder is not a verification code: it holds no secret and carries no urgency. What matters is not that it leaves immediately, but that it arrives at the right moment.

2. Send from a scheduled job

import logging
import os
import time
from datetime import date, timedelta

import requests

API = 'https://api.sms.gworldship.com/v1/sms'
KEY = os.environ['GSMS_API_KEY']
CLINIC = 'Akwa Clinic'
FRONT_DESK = '233 42 10 10'

tomorrow = date.today() + timedelta(days=1)


def post(payload):
    return requests.post(API, timeout=10, json=payload,
                         headers={'Authorization': f'Bearer {KEY}'})


for appointment in appointments_on(tomorrow):
    text = (f'Reminder: your appointment is tomorrow {tomorrow:%d/%m} '
            f'at {appointment.time} at {CLINIC}. To cancel, call {FRONT_DESK}.')

    response = post({
        'to': appointment.phone,                          # +237690000000
        'text': text,
        # One reminder per appointment per date: if the job runs twice, the API
        # answers 409 with the message already sent, no second send or charge.
        'clientReference': f'reminder-{appointment.id}-{tomorrow:%Y%m%d}',
    })

    if response.status_code in (202, 409):
        appointment.save_reminder(response.json()['messageId'])
    else:
        logging.warning('G-SMS %s %s', response.status_code,
                        response.json().get('code'))

    time.sleep(0.2)   # 10 requests per second per key: stay under the limit

The example message is 99 characters in the standard alphabet: a single segment, with 61 characters to spare. The client reference includes the date, which makes the job replayable — run twice on the same day, it does not send two reminders. How idempotency works →

3. Handle by hand what did not get through

# On the morning itself: who did not get their reminder?
failed = requests.get(
    API,
    timeout=10,
    headers={'Authorization': f'Bearer {KEY}'},
    params={'status': 'FAILED', 'from': f'{tomorrow:%Y-%m-%d}T00:00:00Z', 'size': 100},
).json()

for message in failed['content']:
    # The credit is already refunded: what is left to do is human.
    call_list.add(message['clientReference'], message['to'])

An unreachable number stays an unreachable number: the failed SMS is credited back automatically, but it is the front desk that will call. The list is short, and that is precisely the point: manual work now only covers the cases that deserve it.

The real cost, in CFA francs

Assumption: 200 appointments a month. Weighted average price of XAF 5.30, from 85% of sends to Orange and MTN at XAF 5 and 15% to Camtel and Nexttel at XAF 7.

ReminderMonthly volumeMonthly cost
Reminder the day before, at 5 pm200XAF 1,060
Second reminder, two hours ahead (optional)200XAF 1,060
Both reminders400 SMSXAF 2,120

That is XAF 5.30 per appointment reminded once. A single XAF 10,000 slot saved by the reminder pays for more than nine months of sending.

Good practice

  • Between 8 am and 7 pm, never outside. A reminder arriving at 10 pm irritates, and is no longer on screen the next morning.
  • Two reminders at most, and one in most cases. The third message turns a service into harassment.
  • Everything in one sentence: date, time, place and how to cancel. The customer will not read the message twice.
  • Name the practice. The sender shown is a number, not a name: without it the recipient has no idea who is writing.
  • Give a number that is answered. The reminder exists to collect cancellations: if nobody picks up, the slot stays lost.
  • Use a client reference containing the appointment date, not just its identifier: a rescheduled appointment must be allowed a new reminder.
  • Only send for appointments still active. Read the diary at send time, not from an extract frozen the evening before.
  • Stay under 10 requests per second per key. A short pause between sends is enough; beyond that the API answers 429 with a Retry-After header.

What G-SMS does not do

  • No inbound SMS, so no confirmation by reply. The “reply YES to confirm” pattern is impossible: no incoming message is ever read. This is a settled design decision, not a pending feature. Give a phone number or a link, and design the reminder as a statement rather than a question.
  • No custom sender name. The recipient sees the number of the sending SIM. Hence the previous rule: your name has to be in the text.
  • No scheduling on the G-SMS side. There is no “send at this time” field: your scheduled job decides the moment. The API sends when it is called.
  • No diary management. G-SMS knows neither your slots nor your patients: it takes a number and a text, and returns a delivery status.
📵 The sender seen by the recipient is the number of the sending SIM, not a brand name: G-SMS is designed for transactional SMS (OTP codes, notifications), not for marketing campaigns.

Frequently asked questions

How much does an appointment reminder SMS cost in Cameroon?

XAF 5 per segment to Orange and MTN, XAF 7 to Camtel and Nexttel. A reminder of about a hundred characters fits in a single segment, so budget 5 to 7 francs per appointment reminded.

When should the reminder go out?

Late afternoon the day before, while the patient can still free up or move the slot. A reminder sent on the morning itself leaves no time to reorganise the day.

Can the patient confirm by replying to the SMS?

No: G-SMS does not receive messages, by design. Put a phone number or a link in the text instead — and make sure that number is actually answered.

Ready to send your first SMS?

Create an account, get 100 FCFA of credit and an API key straight away.

Create an account