# Vonage

Send text messages (SMS) with Vonage

![infobip.svg](https://zatosource-production.b-cdn.net/docs/gfx/dev/examples/sms/send/vonage/vonage.webp?v=1791904153)

This page will show you how to send text messages through Vonage from Python:

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

## Collecting Vonage config {#collecting-vonage-config}

You'll need three details from the Vonage API dashboard:

- The API key, on the dashboard's home page
- The API secret, on the same page
- The sender, which is a virtual number of the account, such as `12025550100`, or an alphanumeric sender ID in the lands that permit one

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

First, create a Basic Auth definition under `Security → Basic Auth` - the Messages API signs in each request with the API key as the username and the API secret as the password:

| Field | Value |
| --- | --- |
| Name | `Vonage SMS` |
| Username | The API key |
| Password | The API secret |

![Basic Auth for Vonage](https://zatosource-production.b-cdn.net/docs/gfx/sms/send/vonage-basic-auth-create.webp?v=1792089151)

Dashboard menu: Security > Basic Auth

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

| Field | Value | Notes |
| --- | --- | --- |
| Name | `Vonage SMS` | --- |
| Host | `https://api.nexmo.com` | --- |
| URL path | `/v1/messages` | --- |
| Data format | JSON | --- |
| Security | `Basic Auth/Vonage SMS` | The definition just created |

![REST connection to Vonage](https://zatosource-production.b-cdn.net/docs/gfx/sms/send/vonage-rest-create.webp?v=1792089152)

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 Vonage
- Return the ID Vonage gave the message

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

# Zato
from zato.server.service import Service

class SendVonageSMS(Service):

    name = 'sms.vonage.send'
    input = 'to', 'text'

    def handle(self):

        input = self.request.input

        # The message in Vonage's format ..
        message = {
            'message_type': 'text',
            'channel': 'sms',
            'to': input.to,
            'from': '12025550100',
            'text': input.text,
        }

        # .. get the connection to Vonage ..
        conn = self.rest['Vonage SMS']

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

        # .. make sure Vonage accepted it ..
        if not response.ok:
            title = response.data['title']
            detail = response.data['detail']
            raise Exception(f'Vonage error {title}: {detail}')

        # .. and tell our caller the ID of the message.
        message_id = response.data['message_uuid']
        self.response.payload = {'message_id': message_id}
```

Numbers go to Vonage in E.164 form without the leading `+`, so the service is invoked with `{"to": "12025550123", "text": "Your appointment is tomorrow at 9:00"}`.

After invoking the service you'll see:

```json
{"message_id": "aaaaaaaa-bbbb-4ccc-8ddd-0123456789ab"}
```

Vonage answers with `202 Accepted` and the UUID of the message, which means it has been accepted for delivery.

## Errors {#errors}

When Vonage does not accept a message, it answers with a 4xx status and a JSON body whose `title` and `detail` say why, e.g.:

```json
{
  "type": "https://developer.vonage.com/api-errors#unauthorized",
  "title": "Unauthorized",
  "detail": "You did not provide correct credentials.",
  "instance": "bf0ca0bf927b3b52e3cb03217e1a1ddf"
}
```

The service above converts such a response to an exception containing the title and the detail.

## 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
- [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
- [Africa's Talking](https://zato.io/docs/dev/examples/sms/send/africas-talking.html) - Try every message for free in a sandbox that shows it on a simulated phone instead of delivering it
- [Basic Auth](https://zato.io/docs/security/basic-auth.html) - Keep the username and password out of your code - Zato adds them 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
