# Africa's Talking

Send text messages (SMS) with Africa's Talking

This page will show you how to send text messages through Africa's Talking from Python:

- What to collect from the Africa's Talking dashboard
- Which security definition and outgoing REST connection to create
- How to send a message from a service and read the response
- How to test in the sandbox

## Collecting Africa's Talking config {#collecting-africas-talking-config}

You'll need three details from the Africa's Talking dashboard:

- The username of the app, which is `sandbox` in the sandbox
- An API key, generated in the app's Settings → API Key
- Optionally, the sender, which is a sender ID or a short code registered with the account - without one, messages are sent from the default sender of the account

## Creating Zato connections {#creating-zato-connections}

First, create an API key definition under `Security → API keys`. Africa's Talking expects the key in the `apiKey` header:

| Field | Value |
| --- | --- |
| Name | `Africa's Talking SMS` |
| Header | `apiKey` |
| API key | The API key |

![API key for Africa's Talking](https://zatosource-production.b-cdn.net/docs/gfx/sms/send/africas-talking-apikey-create.webp?v=1792089156)

Dashboard menu: Security > API keys

Next, create an outgoing REST connection under `Connections → Outgoing → REST`:

| Field | Value | Notes |
| --- | --- | --- |
| Name | `Africa's Talking SMS` | --- |
| Host | `https://api.africastalking.com` | `https://api.sandbox.africastalking.com` in the sandbox |
| URL path | `/version1/messaging` | --- |
| Data format | Form data | --- |
| Content type | `application/x-www-form-urlencoded` | --- |
| Security | `API key/Africa's Talking SMS` | The definition just created |

![REST connection to Africa's Talking](https://zatosource-production.b-cdn.net/docs/gfx/sms/send/africas-talking-rest-create.webp?v=1792089157)

Dashboard menu: Connections > Outgoing > REST

## Sending a message {#sending-a-message}

The service below will:

- Build the message from the input it received
- Send it to Africa's Talking, asking for a JSON response
- Return the ID the message received and its status

```python
# -*- coding: utf-8 -*-

# stdlib
from http import HTTPStatus

# Zato
from zato.server.service import Service

class SendAfricasTalkingSMS(Service):

    name = 'sms.africas-talking.send'
    input = 'to', 'text'

    def handle(self):

        input = self.request.input

        # The message in the format of Africa's Talking ..
        message = {
            'username': 'riverside',
            'to': input.to,
            'message': input.text,
            'from': 'RIVERSIDE',
        }

        # .. without this header, the response is XML ..
        headers = {'Accept': 'application/json'}

        # .. get the connection to Africa's Talking ..
        conn = self.rest["Africa's Talking SMS"]

        # .. send the message ..
        response = conn.post(message, headers=headers)

        # .. make sure the request was accepted ..
        if not response.ok:
            reason = response.text
            raise Exception(f"Africa's Talking error: {reason}")

        # .. there is one result for each recipient ..
        message_data = response.data['SMSMessageData']
        recipients = message_data['Recipients']
        recipient = recipients[0]

        # .. a rejected recipient has a code of the 4xx or 5xx class ..
        if recipient['statusCode'] >= HTTPStatus.BAD_REQUEST:
            number = recipient['number']
            status = recipient['status']
            raise Exception(f'Rejected {number}: {status}')

        # .. and tell our caller what Africa's Talking said.
        self.response.payload = {
            'message_id': recipient['messageId'],
            'status': recipient['status'],
            'cost': recipient['cost'],
        }
```

After invoking the service you'll see:

```json
{
  "message_id": "ATXid_4f7a2c9e1b3d5f6a8c0e2b4d6f8a1c3e",
  "status": "Success",
  "cost": "KES 0.8000"
}
```

The `to` field can also be several numbers separated by commas, in which case `Recipients` has one result for each of them.

## Status codes {#status-codes}

Each recipient in the response has a `statusCode` and a `status`:

| Status code | Status | Meaning |
| --- | --- | --- |
| 100 | `Processed` | Accepted |
| 101 | `Success` | Accepted and sent |
| 102 | `Queued` | Accepted and queued for delivery |
| 401 | `RiskHold` | Held for review |
| 402 | `InvalidSenderId` | The sender is not registered with the account |
| 403 | `InvalidPhoneNumber` | The number is not valid |
| 405 | `InsufficientBalance` | The account has no credit left |
| 406 | `UserInBlacklist` | The recipient has opted out of messages |

## Testing in the sandbox {#testing-in-the-sandbox}

The sandbox accepts messages as the live API does, but it does not deliver them, and nothing is charged for. The messages sent appear in the simulator of the Africa's Talking dashboard, which acts as a phone with the number the message was sent to.

To use it, create a second API key definition and REST connection, with:

- The API key generated in the sandbox app
- The host set to `https://api.sandbox.africastalking.com`
- `sandbox` as the username in the message

## See also {#see-also}

- [How to send text messages (SMS)](https://zato.io/docs/dev/examples/sms/send/tutorial.html) - Send every text from one service, so a change of provider later means editing that service alone
- [Twilio](https://zato.io/docs/dev/examples/sms/send/twilio.html) - Send through Twilio and test for free with credentials that never deliver or charge for a message
- [Vonage](https://zato.io/docs/dev/examples/sms/send/vonage.html) - Send through Vonage with your organization's name as the sender, in countries that allow one
- [Infobip](https://zato.io/docs/dev/examples/sms/send/infobip.html) - Tell everyone at once - one request sends the same text to any number of recipients
- [API keys](https://zato.io/docs/security/api-keys.html) - Keep the API key out of your code - Zato adds it to every request the connection makes
- [Calling external REST APIs](https://zato.io/docs/dev/rest/calling-apis.html) - Call any other REST API the same way, with parameters, headers and status checks

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - The complete reference for writing services
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how both are structured
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
