openapi: 3.0.0
servers:
  - url: https://api.bulksms.com/v1
info:
  description: |
    ## Overview

    The JSON REST API allows you to submit and receive [BulkSMS](https://www.bulksms.com/) messages. You can also get access to past messages and see your account profile.

    The base URL to use for this service is `https://api.bulksms.com/v1`.  The base URL cannot be used on its own; you must append a path that identifies an operation and you may have to specify some path parameters as well.

    [Click here](/developer/) to go to the main BulkSMS developer site.

    In order to give you an idea on how the API can be used, some JSON snippets are provided below.  Have a look at the [messages section](#tag/Message) for more information.

    Probably the most simple example

    ```
    {
        "to": "+27001234567",
        "body": "Hello World!"
    }
    ```


    You can send unicode automatically using the `auto-unicode` query parameter. 
    Alternatively, you can specify `UNICODE` for the `encoding` property in the request body. 
    Please note: when `auto-unicode` is specified and the value of the `encoding` property is `UNICODE`, the message will always be sent as `UNICODE`.

    Here is an example that sets the `encoding` explicitly

    ```
    {
      "to": "+27001234567",
      "body": "Dobrá práce! Jak se máš?",
      "encoding": "UNICODE"
    }
    ```

    You can also specify a from number

    ```
    {
        "from": "+27007654321",
        "to": "+27001234567",
        "body": "Hello World!"
    }
    ```

    Similar to above, but repliable

    ```
    {
        "from": { "type": "REPLIABLE" },
        "to": "+27001234567",
        "body": "Hello World!"
    }
    ```

    A message to a group called Everyone

    ```
    {
        "to": { "type": "GROUP", "name": "Everyone" },
        "body": "Hello World!"
    }
    ```

    A message to multiple recipients

    ```
    {
        "to": ["+27001234567", "+27002345678", "+27003456789"],
        "body": "Happy Holidays!"
    }
    ```

    Sending more than one message in the same request

    ```
    [
        {
            "to": "+27001234567",
            "body": "Hello World!"
        },
        {
            "to": "+27002345678",
            "body": "Hello Universe!"
        }
    ]
    ```

    **The insecure base URL `http://api.bulksms.com/v1` is deprecated** and may in future result in a `301` redirect response, or insecure requests may be rejected outright. Please use the secure (`https`) URI above.

    ### HTTP Content Type

    All API methods expect requests to supply a `Content-Type` header with the value `application/json`. All responses will have the `Content-Type` header set to `application/json`.

    ### JSON Formatting

    You are advised to format your JSON resources according to strict JSON format rules. While the API does attempt to parse strictly invalid JSON documents, doing so may lead to incorrect interpretation and unexpected results.

    Good JSON libraries will produce valid JSON suitable for submission, but if you are manually generating the JSON text, be careful to follow the JSON format. This include correct escaping of control characters and double quoting of property names.

    See the [JSON specification](https://tools.ietf.org/html/rfc4627) for further information.

    ### Date Formatting

    Dates are formatted according to ISO-8601, such as `1970-01-01T10:00:00+01:00` for 1st January 1970, 10AM UTC+1.

    See the [Wikipedia ISO 8601 reference](https://en.wikipedia.org/wiki/ISO_8601) for further information.

    Specifically, calendar dates are formatted with the 'extended' format `YYYY-MM-DD`. Basic format, week dates and ordinal dates are not supported. Times are also formatted in the 'extended' format `hh:mm:ss`. Hours, minutes and seconds are mandatory. Offset from UTC must be provided; this is to ensure that there is no misunderstanding regarding times provided to the API.

    The format we look for is `yyyy-MM-ddThh:mm:ss[Z|[+-]hh:mm]`

    Examples of valid date/times are`2011-12-31T12:00:00Z` `2011-12-31T12:00:00+02:00`

    ### Entity Format Modifications

    It is expected that over time some changes will be made to the request and response formats of various methods available in the API.
    Where possible, these will be implemented in a backwards compatible way.
    To make this possible you are required to ignore unknown properties.
    This enables the addition of information in response documents while maintaining compatibility with older clients.

    ### Optional Request Entity Properties

    There are many instances where requests can be made without having to specify every single property allowable in the request format.
    Any such optional properties are noted as such in the documentation and their default value is noted.
  title: BulkSMS JSON REST API
  version: 1.0.0
  x-apisguru-categories:
    - telecom
  x-logo:
    url: https://api.apis.guru/v2/cache/logo/_developer_images_bulksms.svg
  x-origin:
    - format: openapi
      url: http://developer.bulksms.com/json/v1/swagger.yaml
      version: "3.0"
  x-providerName: bulksms.com
security:
  - basicAuth: []
tags:
  - name: Message
    x-displayName: Messages
  - name: Profile
    x-displayName: Profile
paths:
  /blocked-numbers:
    get:
      parameters:
        - description: Records with an `id` that is greater or equal to min-id will be returned. The default value is `0`.  You can add 1 to an id that you previously retrieved, to return subsequent records.
          in: query
          name: min-id
          schema:
            format: int32
            type: integer
        - description: The maximum number of records to return. The default value is `10000`. The value cannot be greater than 10000.
          in: query
          name: limit
          schema:
            format: int32
            type: integer
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BlockedNumber"
          description: A list of BlockedNumber objects
      security:
        - basicAuth: []
      summary: List blocked numbers
      tags:
        - Blocked Numbers
    post:
      description: |
        Blocked numbers are phone numbers to which your account is not permitted to send messages.
        The numbers can be created via this API, by a recipient replying with a STOP message to one
        of your previous SENT messages, or by a BulkSMS administrator.

        Sending a message to a blocked number will result in the message being assigned a status of
        `FAILED.BLOCKED`. Messages sent to blocked numbers are billed to your account.
      requestBody:
        content:
          application/json:
            schema:
              items:
                $ref: "#/components/schemas/PhoneNumber"
              type: array
        description: "Maximum size: `1000` items"
        required: true
      responses:
        "200":
          description: Empty body upon success
      security:
        - basicAuth: []
      summary: Create a blocked number
      tags:
        - Blocked Numbers
  /credit/transfer:
    post:
      description: |
        Before you can use the transfer credits endpoint, the _credit-transfer facility_ must be activated for your account.  You can request activation from `support@bulksms.com`. 

        The recipient must be an enabled account that uses the same currency as your account.
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransferEntry"
        description: |
          Contains details of the transfer request.
        required: true
      responses:
        "200":
          description: An empty body when the credits were transferred OK.
        "400":
          description: When the request fails validation checks.
        "403":
          description: When there are not enough credits in your account or the credit transfer facility is not activated.
      security:
        - basicAuth: []
      summary: Transfer credits to another account
      tags:
        - Credits
  /messages:
    get:
      description: |
        Retrieve the messages you have sent or received.  

        Scheduled messages are available for retrieval only after the delivery date.

        All the parameters are optional.  If a value is not supplied for `filter`, the messages are not filtered.

        Messages can be filtered by supplying query clauses in the `filter` parameter. Each clause has the form `name=value` where `name` is the name of a filter field and `value` is a valid value for that field.  A value for a field is optional. Include a clause for a field in the filter only when there is a need to fetch messages that match some value for that field.
        For a numeric filter field, you can also use the less than operator (`<`).

        If present, the filter value must have at least one clause, but it can contain a combination of clauses. Multiple clauses are separated with the `&` symbol.  Semantically, multiple clauses form a [logical conjunction](https://en.wikipedia.org/wiki/Logical_conjunction).

        For example, if you want to list all messages that were sent as part of a particular submission, your filter contains two clauses and will look something like this
        ```
        type%3DSENT&submission.id%3D1-00000000000522347562
        ```
        Because `filter` is a request parameter, it is important to note that the value for this parameter must be *URL encoded*. In particular, the `=` encodes to `%3D` and the `&` encodes to `%26`.  Note that you do not have to encode the `<` character.

        Using the previous example to illustrate; after encoding and encasing it, the clauses are transformed into a request that looks like this
        ```
        GET /v1/messages?filter=type%3DSENT%26submission.id%3D1-00000000000522347562
        ```
        If the field name or the field value of a clause is not valid, a [bad_request error](errors#bad-request) is returned instead of the usual result.  The `detail` field of this error provides more information about the problem.

        The table below lists the fields available for filtering

        | Field | Type   | Values | Note and example |
        |-------|------|--------------------|------|
        | id            | Integer  | Positive integer  | Use the `id` field with `<` (or with `>`) to fetch messages that are older (or newer) than those that are already fetched. <br/>`filter=id<123456` |
        | type          | String  | SENT, RECEIVED  | SENT are Mobile Terminating (MT) SMSs; RECEIVED are Mobile Originating (MO) SMSs.<br/>`filter=type%3DSENT` |
        | submission.id | String  |  | `filter=submission.id%3D1-00000000000522347562` |
        | status.type   | String  | ACCEPTED, SENT, DELIVERED, FAILED  | See the message `status.type` field for more information. <br/>`filter=status.type%3DDELIVERED` |
        | status.id| String  |  | See the message `status.id` field for more information. `filter=status.id%3DFAILED.EXPIRED`|
        | submission.date | String | Formatted Date | A fully specified date (e.g. 2017-01-01T10:00:00+01:00).  Use this field with `<=`, `<`, `>` or `>=` to limit the values. <br/>`filter=submission.date%3E%3D2017-01-01T10%3A00%3A00%2B01%3A00` |
        | userSuppliedId  | String | | Use a string value you specified in the `userSuppliedId` property when you sent the message. Only `SENT` messages will be retrieved. <br/>`filter=userSuppliedId%3Dacc009876` |
      parameters:
        - description: |-
            The maximum number of messages that are returned.  The default is 1000.
            The value of `limit` is not a guarantee that a specific number of messages will be in the response, even if there are more messages available.  Consider the case where you have 150 messages and you specify `limit=50`.  It is possible that only 49 messages will be returned.  The  way to make sure that there are no more messages is to submit a new call using the `id` filter field with the `<` operator (described below).
          in: query
          name: limit
          required: false
          schema:
            format: int
            type: number
        - description: See the message filtering for more information.
          in: query
          name: filter
          schema:
            type: string
        - description: |
            The default value is DESCENDING

            If the `sortOrder` is DESCENDING, the newest messages be first in the result.  ASCENDING places the oldest messages on top of the response.
          in: query
          name: sortOrder
          schema:
            enum:
              - ASCENDING
            type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/components/schemas/Message"
                type: array
          description: Contains the requested array of messages
        "400":
          $ref: "#/components/responses/bad-request"
      security:
        - basicAuth: []
      summary: Retrieve Messages
      tags:
        - Message
      x-code-samples:
        - lang: C#
          source: |
            using System;
            using System.IO;
            using System.Net;

                class MainClass
                {

                    public static void Main(string[] args)
                    {
                        /** 
                        Note in the query string 
                        we have a filter to get only the 
                        SENT messages
                        */
                        string myURI = "https://api.bulksms.com/v1/messages?filter=type%3DSENT";
                        string myUsername = "username";
                        string myPassword = "yourPassword";
                        var request = WebRequest.Create(myURI);
                        request.Credentials = new NetworkCredential(myUsername, myPassword);
                    request.PreAuthenticate = true;
                        request.Method = "GET";
                        request.ContentType = "application/json";
                        try
                        {
                            // make the call to the API
                            var response = request.GetResponse();

                            // read the response and print it to the console
                            var reader = new StreamReader(response.GetResponseStream());
                            Console.WriteLine(reader.ReadToEnd());

                        }  catch (WebException ex) {
                    // show the general message
                    Console.WriteLine("An error occurred:" + ex.Message);

                            // print the detail that come with the HTTP error 
                            var reader = new StreamReader(ex.Response.GetResponseStream());
                            Console.WriteLine("Error details:" + reader.ReadToEnd());
                        }
                }
            }
    post:
      description: |
        Send messages to one or more recipients.

        You can post up to `30 000` messages in a batch. 
        But note that the `deduplication-id` is set per submission, so it is recommended that you use a smaller number, like `4000` per submission in order to make resubmissions on network failures more practical.

        #### Repliability

        When a sent message is _repliable_,  the BulkSMS system can process an SMS response sent by your recipient.

        The message sent by your customer is called a mobile originating (MO) message and would be available under `RECEIVED` messages. 
        You can obtain a list of MOs using the [retrieve messages API call](#tag/Message%2Fpaths%2F~1messages%2Fget).
        In addition you can also get a list of the MOs that are associated with a specific sent message (see the [list related messages API call](#tag/Message%2Fpaths%2F~1messages~1%7Bid%7D~1relatedReceivedMessages%2Fget)).

        If you use a specific _sender id_ in the `from` property of the send message, the message will not be repliable.
        If you want a message to be repliable, you need to specify `REPLIABLE` in the `from.type` property.

        If you do not set the `from` property, your account settings are considered to determine whether or not the message is repliable.
        If the _default repliable_ setting on your account is _yes_ then the message will be repliable. 
        If this setting is _no_, the message will not be repliable.


        #### Body templates

        When sending a message you can use template fields to customise the message text.

        *Field based templates* allow you to create a message with place-holders for custom fields.  Fields are identified by a zero based index; the first field is `F0`, the second is `F1` and so on.  

        For example, let's say you want to send a daily SMS message to all your clients that tell them what their current balance is.  The `body` of the message could look something like this 

        ```
        Good morning {F0######}, your balance is {F1######}
        ```

        In this message, the first field, `F0`, is the name  of the customer and he second field `F1` is the balance for that customer.  The `#` used to specify the maximum length  of the field.  Note that the maximum length allowed for the value includes the space taken by the braces, template name and hash symbol.  For example, the value `{F0#}` specifies a maximum length of `5`.  If the data is longer than this length, the data will be truncated when the message body is constructed.

        The data fields are provided in the property named `fields` in the `to` element.  Here is a complete example of how this might look

        ```
        {
          "body": "Good morning {F0######}, your balance is {F1######}",
          "to":  [
              {"address": "27456789","fields": ["Harry", "$1345.23"] },
              {"address": "27456785","fields": ["Sally", "$2345.58"] }
          ]
        }
        ```

        If you are sending to contacts (or to groups) in your phonebook, you can use the *Phonebook based templates*.  These are similar to the templates described above, but they have specific names. The template for the contact's first name is identified by `fn` and the template for the contact's surname is identified by `sn`.  Below in an example that will work if the numbers are registered in your phonebook. 

        ```
        {
          "body": "Hi {fn######} {sn######}, have a great day!",
          "to":  [
              {"address": "27456789" },
              {"address": "27456785" }
          ]
        }
        ```
      parameters:
        - description: |
            Safeguards against the possibility of sending the same messages more than once.

            If a communication failure occurs during a submission, you cannot be sure that the submission was processed; therefore you would have to submit it again. When you post the retry, you must use the `deduplication-id` of the original post. The BulkSMS system uses this ID to check that the request was not previously processed. (If it was previously processed, the submission will succeed, and the behaviour will be indistinguishable to you from a non-duplicated submission). The ID expires after about 12 hours.
          in: query
          name: deduplication-id
          schema:
            format: int32
            type: integer
        - description: |
            Specifies how to deal with message text that contains characters not present in the GSM 03.38 character set.

            Messages that contain only GSM 03.38 characters are not affected by this setting. 
            If the value is `true` then a message containing non-GSM 03.38 characters will be transmitted as a Unicode SMS (which is most likely more costly). 

            Please note: when `auto-unicode` is `true` and the value of the `encoding` property is specified as `UNICODE`, the message will always be sent as `UNICODE`.

            If the value is `false` and the `encoding` property is `TEXT` then non-GSM 03.38 characters will be replaced by the `?` character.

            When using this setting on the API, you should take case to ensure that your message is _clean_.  

            Invisible unicode and unexpected characters could unintentionally convert an message to `UNICODE`.  A common mistake is to use the backtick character (\`) which is unicode and will turn your `TEXT` message into a `UNICODE` message.
          in: query
          name: auto-unicode
          schema:
            default: false
            type: boolean
        - description: |
            Allows you to send a message in the future.

            An example value is `2019-02-18T13:00:00+02:00`.  It encodes to `2019-02-18T13%3A00%3A00%2B02%3A00`.
            Credits are deducted from your account immediately. Once submitted, scheduled messages cannot be changed or cancelled.
            The date can be a maximum of two years in the future. If the value is in the past, the message will be sent immediately.
            The date format requires you to supply an offset from UTC. You can decide to use the offset of your timezone, or maybe the zone of the recipient's location is more appropriate.
            If the destination is a group, the group members are determined at the time that you submit the message; not the time the message is scheduled to be sent.
          in: query
          name: schedule-date
          schema:
            format: date-time
            type: string
        - description: |
            A note that is stored together with a scheduled submission, which could be used to more easily identify the scheduled submission at a later date.

            The value of this field is ignored if the `schedule-date` is not provided.
            A value that is longer than 256 characters is truncated.
          in: query
          name: schedule-description
          schema:
            type: string
      requestBody:
        content:
          application/json:
            schema:
              items:
                $ref: "#/components/schemas/SubmissionEntry"
              type: array
        description: |
          Contains details of the message (or messages) that you want to send.

          One `SubmissionEntry` can produce many messages, and your request may contain multiple such entries.
        required: true
      responses:
        "201":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/components/schemas/Message"
                type: array
          description: An array of the messages that were created from the request
        "400":
          $ref: "#/components/responses/bad-request"
        "403":
          $ref: "#/components/responses/credits"
      security:
        - basicAuth: []
      summary: Send Messages
      tags:
        - Message
      x-code-samples:
        - lang: PHP
          source: |
            <?
            // Your PHP installation needs cUrl support, which not all PHP installations
            // include by default.
            // To run under docker:
            // docker run -v $PWD:/code php:7.3.2-alpine php /code/code_sample.php

            $username = 'your_username';
            $password = 'your_password';
            $messages = array(
              array('to'=>'+1233454567', 'body'=>'Hello World!'),
              array('to'=>'+1233454568', 'body'=>'Hello World!')
            );  

            $result = send_message( json_encode($messages), 'https://api.bulksms.com/v1/messages?auto-unicode=true&longMessageMaxParts=30', $username, $password );

            if ($result['http_status'] != 201) {
              print "Error sending: " . ($result['error'] ? $result['error'] : "HTTP status ".$result['http_status']."; Response was " .$result['server_response']);
            } else {
              print "Response " . $result['server_response'];
              // Use json_decode($result['server_response']) to work with the response further
            }

            function send_message ( $post_body, $url, $username, $password) {
              $ch = curl_init( );
              $headers = array(
              'Content-Type:application/json',
              'Authorization:Basic '. base64_encode("$username:$password")
              );
              curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
              curl_setopt ( $ch, CURLOPT_URL, $url );
              curl_setopt ( $ch, CURLOPT_POST, 1 );
              curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
              curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_body );
              // Allow cUrl functions 20 seconds to execute
              curl_setopt ( $ch, CURLOPT_TIMEOUT, 20 );
              // Wait 10 seconds while trying to connect
              curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 10 );
              $output = array();
              $output['server_response'] = curl_exec( $ch );
              $curl_info = curl_getinfo( $ch );
              $output['http_status'] = $curl_info[ 'http_code' ];
              $output['error'] = curl_error($ch);
              curl_close( $ch );
              return $output;
            } 
            ?>         
        - lang: C#
          source: |
            using System;
            using System.IO;
            using System.Net;
            using System.Text;

            class MainClass
            {
                public static void Main(string[] args)
                {
                    // This URL is used for sending messages
                    string myURI = "https://api.bulksms.com/v1/messages";

                    // change these values to match your own account
                    string myUsername = "username";
                    string myPassword = "password";

                    // the details of the message we want to send
                    string myData = "{to: \"1111111\", body:\"Hello Mr. Smith!\"}";

                    // build the request based on the supplied settings
                    var request = WebRequest.Create(myURI);

                    // supply the credentials
                    request.Credentials = new NetworkCredential(myUsername, myPassword);
                    request.PreAuthenticate = true;
                    // we want to use HTTP POST
                    request.Method = "POST";
                    // for this API, the type must always be JSON
                    request.ContentType = "application/json";

                    // Here we use Unicode encoding, but ASCIIEncoding would also work
                    var encoding = new UnicodeEncoding();
                    var encodedData = encoding.GetBytes(myData);

                    // Write the data to the request stream
                    var stream = request.GetRequestStream();
                    stream.Write(encodedData, 0, encodedData.Length);
                    stream.Close();

                    // try ... catch to handle errors nicely
                    try
                    {
                        // make the call to the API
                        var response = request.GetResponse();

                        // read the response and print it to the console
                        var reader = new StreamReader(response.GetResponseStream());
                        Console.WriteLine(reader.ReadToEnd());
                    }
                    catch (WebException ex)
                    {
                        // show the general message
                        Console.WriteLine("An error occurred:" + ex.Message);

                        // print the detail that comes with the error
                        var reader = new StreamReader(ex.Response.GetResponseStream());
                        Console.WriteLine("Error details:" + reader.ReadToEnd());
                    }
                }
            }
        - lang: Java
          source: |
            import java.net.*;
            import java.util.Base64;
            import java.io.*;

            public class MainClass {

              static public void main(String[] args) throws Exception {

                // This URL is used for sending messages
                String myURI = "https://api.bulksms.com/v1/messages";

                // change these values to match your own account
                String myUsername = "username";
                String myPassword = "password";

                // the details of the message we want to send
                String myData = "{to: \"1111111\", encoding: \"UNICODE\", body: \"Dobrá práce! Jak se máš?\"}";

                // if your message does not contain unicode, the "encoding" is not required:
                // String myData = "{to: \"1111111\", body: \"Hello Mr. Smith!\"}";

                // build the request based on the supplied settings
                URL url = new URL(myURI);
                HttpURLConnection request = (HttpURLConnection) url.openConnection();
                request.setDoOutput(true);

                // supply the credentials
                String authStr = myUsername + ":" + myPassword;
                String authEncoded = Base64.getEncoder().encodeToString(authStr.getBytes());
                request.setRequestProperty("Authorization", "Basic " + authEncoded);

                // we want to use HTTP POST
                request.setRequestMethod("POST");
                request.setRequestProperty( "Content-Type", "application/json");

                // write the data to the request
                OutputStreamWriter out = new OutputStreamWriter(request.getOutputStream());
                out.write(myData);
                out.close();

                // try ... catch to handle errors nicely
                try {
                  // make the call to the API
                  InputStream response = request.getInputStream();
                  BufferedReader in = new BufferedReader(new InputStreamReader(response));
                  String replyText;
                  while ((replyText = in.readLine()) != null) {
                    System.out.println(replyText);
                  }
                  in.close();
                } catch (IOException ex) {
                  System.out.println("An error occurred:" + ex.getMessage());
                  BufferedReader in = new BufferedReader(new InputStreamReader(request.getErrorStream()));
                  // print the detail that comes with the error
                  String replyText;
                  while ((replyText = in.readLine()) != null) {
                    System.out.println(replyText);
                  }
                  in.close();
                }
                request.disconnect();
              }
            }
        - lang: Node.js
          source: |
            const https = require('https');

            let username = 'your_username';
            let password = 'your_password';

            let postData = JSON.stringify({
              'to' : ['+111111123', '+111111124'],
              'body': 'Hello World!'
            });

            let options = {
              hostname: 'api.bulksms.com',
              port: 443,
              path: '/v1/messages',
              method: 'POST',
              headers: {
                'Content-Type': 'application/json',
                'Content-Length': postData.length,
                'Authorization': 'Basic ' + Buffer.from(username + ':' + password).toString('base64')
              }
            };

            let req = https.request(options, (resp) => {
              console.log('statusCode:', resp.statusCode);
              let data = '';
                resp.on('data', (chunk) => {
                data += chunk;
              });
              resp.on('end', () => {
                console.log("Response:", data);
              });
            });

            req.on('error', (e) => {
              console.error(e);
            });

            req.write(postData);
            req.end();
  /messages/send:
    get:
      description: |
        A really simple interface for people who require a GET mechanism to submit a single message.

        The URI is interpreted as UTF-8. HTTP Basic Auth is used for authentication.

        __Note__ BulkSMS recommends that you use the more flexible Send Messages Operation when submitting SMS messages from your application.

        Here is an example of a GET
        ```http
        GET /v1/messages/send?to=%2b270000000&body=Hello%20World
        ```

        You can also use the same parameters to POST form encoded fields to `/messages`.
        Here is an example of a POST
        ```http
        POST /v1/messages
        Content-Type: application/x-www-form-urlencoded

        to=%2b27000000000&body=Hello+World
        ```
      parameters:
        - description: The phone number of the recipient.
          in: query
          name: to
          required: true
          schema:
            type: string
        - description: The text you want to send.
          in: query
          name: body
          required: true
          schema:
            type: string
        - description: Refer to the `deduplication-id` parameter.
          in: query
          name: deduplication-id
          schema:
            format: int-32
            type: integer
      responses:
        "201":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/components/schemas/Message"
                type: array
          description: An array of messages
        "400":
          $ref: "#/components/responses/bad-request"
        "403":
          $ref: "#/components/responses/credits"
      security:
        - basicAuth: []
      summary: Send message by simple GET or POST
      tags:
        - Message
  "/messages/{id}":
    get:
      description: |
        Get a the message by `id`.
        ```http
        GET /v1/messages/4023457654
        ```
      parameters:
        - description: The `id` of the message you want to retrieve
          in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Message"
          description: The message detail
        "400":
          $ref: "#/components/responses/bad-request"
        "404":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
          description: A [not-found error](errors/#not-found) if the message cannot be found.
      summary: Show Message
      tags:
        - Message
  "/messages/{id}/relatedReceivedMessages":
    get:
      description: |
        Get the messages related to a sent message identified by `id`.

        For more information how this work, see the `relatedSentMessageId` field in the message.
      parameters:
        - description: The `id` of the sent message
          in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/components/schemas/Message"
                type: array
          description: An array of related messages.  If the `id` is not a sent message, the array will be empty.
        "400":
          $ref: "#/components/responses/bad-request"
      security:
        - basicAuth: []
      summary: List Related Messages
      tags:
        - Message
  /profile:
    get:
      description: Returns information about your user profile
      responses:
        "200":
          content:
            application/json:
              examples:
                response:
                  value: null
              schema:
                $ref: "#/components/schemas/Profile"
          description: A Profile object
      security:
        - basicAuth: []
      summary: Get profile
      tags:
        - Profile
  /rmm/pre-sign-attachment:
    post:
      description: |
        When composing an SMS, you can add SMS attachments by adding a URL to your text. When the recipient clicks on the URL, the attached file will be downloaded and opened on their mobile device.  

        The best way to do this is to store the file on a web server you own and use that URL in the SMS text. This URL will be easily recognisable to your message recipient and ties your message back to your brand or company. 

        If that’s not possible, you can use BulkSMS storage to keep the files that you want to attach to your SMS. These files will be deleted after 30 days as per our fair use policy.  

        We recommend you keep this file size below 20 MB, as larger files may be deleted without warning. 

        To use the BulkSMS storage, follow these three steps:

        **Step 1**: Use your BulkSMS credentials (or your API Token) to request a pre-signed URL.  This is what this `pre-sign-attachment` method is for.  It returns a PreSignInfo object that you will use in the other two steps.

        **Step 2**: Upload the file using a standard HTTP `PUT` request. For your `PUT` request, use the value of `putURL` from the PreSignInfo object as the request address.  You also have to add the entries from the `fields` property (of the PreSignInfo object) to the headers of your 'PUT' request. You send the file content as the body of the `PUT` request.

        **Step 3**: Now you can use the value of `fetchURL` from the PreSignInfo object in the body of your SMS messages and send those using the usual messaging API (described elsewhere in this document).  If you send the same file to many recipients, it is safe to use the same URL for all of them.

        If you need to, take a closer look at the example program (on the right-hand side) to get a better idea of how to implement this process.
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PreSignRequest"
        description: Describes the file to upload
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PreSignInfo"
          description: A PreSignInfo object
      security:
        - basicAuth: []
      summary: Upload an attachment via a signed URL
      tags:
        - Attachments
      x-code-samples:
        - lang: C#
          source: |
            using System;
            using System.IO;
            using System.Net;
            using System.Text;
            using System.Text.Json;

            namespace AttachmentUpload
            {
                class MainClass
                {
                    // IMPORTANT: change these constants to match your environment
                    const string myUsername = "username";
                    const string myPassword = "password";
                    const string myPhoneNumber = "1111111";
                    const string myFilePath = "path/to/file.pdf";
                    const string myMediaType = "application/pdf";
                    const string myFileExtension = "pdf";

                    public static void Main(string[] args)
                    {
                        try
                        {
                            // get authorisation (pre-signed URL)
                            var signDetails = getSignedDetails(myFileExtension, myMediaType);
                            // upload and send the file to the signed URL
                            sendFile(signDetails, myFilePath);
                            // send your messages using the provided URL
                            sendMessage(myPhoneNumber, "Attachment test`: " + signDetails.fetchUrl);
                            Console.WriteLine($"Message sent that contains URL to file: {signDetails.fetchUrl}");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("An error occurred:\n" + ex.Message);
                        }
                    }

                    public static void sendFile(PreSignInfo signDetails, string filePath)
                    {
                        using (WebClient client = new WebClient())
                        {
                            foreach (var f in signDetails.fields)
                            {
                                client.Headers.Add(f.name, f.value);
                            }
                            using (Stream fileStream = File.OpenRead(filePath))
                            using (Stream requestStream = client.OpenWrite(new Uri(signDetails.putUrl), "PUT"))
                            {
                                fileStream.CopyTo(requestStream);
                            }
                        }
                    }

                    public static PreSignInfo getSignedDetails(string extension, string mediaType)
                    {
                        string postMessageUrl = "https://api.bulksms.com/v1/rmm/pre-sign-attachment";
                        string requestBody = $"{{fileExtension: '{extension}', mediaType: '{mediaType}'}}";
                        var result = postJson(postMessageUrl, requestBody);
                        return JsonSerializer.Deserialize<PreSignInfo>(result);
                    }

                    public static string sendMessage(string phoneNumber, string messageText)
                    {
                        string postMessageUrl = "https://api.bulksms.com/v1/messages?auto-unicode=true";
                        string requestBody = $"{{to: '{myPhoneNumber}', body: '{messageText}'}}";
                        return postJson(postMessageUrl, requestBody);
                    }


                    public static string postJson(string url, string jsonBody)
                    {
                        var request = WebRequest.Create(url);
                        var encoding = ASCIIEncoding.UTF8;
                        var auth = $"{myUsername}:{myPassword}";
                        var authBase64 = Convert.ToBase64String(encoding.GetBytes(auth));
                        request.Headers.Add("Authorization", "Basic " + authBase64);
                        request.Method = "POST";
                        request.ContentType = "application/json";
                        var encodedData = encoding.GetBytes(jsonBody);
                        var stream = request.GetRequestStream();
                        stream.Write(encodedData, 0, encodedData.Length);
                        stream.Close();
                        try
                        {
                            var response = request.GetResponse();
                            var reader = new StreamReader(response.GetResponseStream());
                            return reader.ReadToEnd();
                        }
                        catch (WebException ex)
                        {
                            var reader = new StreamReader(ex.Response.GetResponseStream());
                            throw new Exception(reader.ReadToEnd());
                        }

                    }

                }

                class NameValue
                {
                    public string name { get; set; }
                    public string value { get; set; }
                }

                class PreSignInfo
                {
                    public string putUrl { get; set; }
                    public string fetchUrl { get; set; }
                    public NameValue[] fields {get;set;}

                }
            }
  /webhooks:
    get:
      description: Contains a list of your webhooks
      responses:
        "200":
          content:
            application/json:
              schema:
                items:
                  $ref: "#/components/schemas/Webhook"
                type: array
          description: Array of Webhooks
      security:
        - basicAuth: []
      summary: List webhooks
      tags:
        - Webhooks
    post:
      description: |
        A webhook is an URL that you can register when you want the BulkSMS system to notify you about your messages.
        You can register multiple webhooks, and each one will be called.  (Note: you can also use our [Web App](https://www.bulksms.com/account/#!/advanced-settings/webhooks) to manage your webhooks interactively.)  
        If you want to be notified of `SENT` messages and `RECEIVED` messages you need to create two webhooks.


        ### Implementing your webhook

        Code samples of Webhook implementations:
        * [PHP](samples/webhook-php.html)

        When you implement your webhook, there are a few rules to be aware of:
        - Your webhook must process `POST` requests that contains an array of messages in the post body.  This input given to your webhook has the same structure as the output produced when you call [Retrieve Messages](#tag/Message%2Fpaths%2F~1messages%2Fget).
        - When you register or update your webhook, the URL will be tested by invoking it with an empty array (`[]`). 
        - It is possible for your webhook to receive multiple updates for the same message and status. It happens from time to time that the mobile network duplicates status updates.
        - The order by which the webhook is invoked can be unexpected.  For example, if sender A replies before sender B, your webhook might get the reply from B first.
        - The webhook is expected to comply with good practices with regard to the status code it responds with.
          - A status code in the `1xx` and `2xx` range is taken as an acknowledgement that the invocation was received and that the webhook host is ready to receive another.
          - A status code in the `4xx` range is taken as a permanent problem and indicates that the webhook cannot process the message. The specific message that caused the error will be discarded, but your webhook will be invoked again when another message becomes available.
          - Any other status code will be taken as a temporary problem; and indicates that the BulkSMS system should retry. The specific message that caused the error will not be discarded and your webhook will be invoked again with this message (see the subsequent section for more details on retry processing).
        - Your webhook has to respond within `30` seconds.  If no response is given in this time, the invocation will be retried.
        - It is good idea to add a secret to your URL in order to make it more secure. Here is an example:
        `https://www.example.com/hook.php?secret=pass763265word`
        - You can use a non-standard port if necessary, for example: `https://www.example.com:8321/hook.php?secret=pass763265word`
        - Your webhook can be called from a dynamic range of IP addresses, and you should be prepared to accept that the source IP can change in the future, without notice. This practice has become common with cloud-hosted solutions. If this is an insurmountable problem for your organisation, please contact support.

        ### Testing and troubleshooting        

        Use `curl` to test your webhook.  The command below is a template that shows how the BulkSMS system invokes your code. It must return `200` for your URL before you can register it as a webhook. 

        ```
        curl -i -X POST 'YOUR_URL_HERE' --header 'Content-Type: application/json' --header 'User-Agent: BulkSMS Invoker' --data-raw '[]'
        ```

        When a `200` is returned for an empty array, modify the template to post multiple messages by adding JSON between the square brackets ('[]').

        After your webhook is successfully registered, you can send a message to `1111111` for an end-to-end test.  The delivery to this test number will fail, but your webhook will be invoked (and there are no charges).  

        ### The retry process

        The process the BulkSMS systems follow to handle retries is roughly the following:
        - The first retry is scheduled for 90 seconds into the future.
        - After the first retry, subsequent failures will have longer delays, following this sequence - 3 minutes, 6 minutes, 12 minutes thereafter the message will be retried every 15 minutes for a 2 day period.
        - When all retries fail, the message will be discarded.

        ### Problem reports via email

        Your are strongly advised to provide an email address when you register your webhook.
        A notice will be sent to this email address to keep you in the loop whenever there are problems with your webhook.
        In order to prevent your inbox from being flooded, the system sends a notice about an observed error no more than once in a 24 hour period.

        The following emails can be expected
         - A __message retrying__ email is sent after an invocation has failed with a retry-able error.  This email is an early warning, allowing you to investigate your systems.
         - A __message discarded__ email is sent after failure email is send when a message is discarded as a consequence of a non-retry-able error.
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEntry"
        description: |
          Contains the property values for your new webhook
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
          description: Contains the webhook you created
        "400":
          $ref: "#/components/responses/bad-webhook-url"
      security:
        - basicAuth: []
      summary: Create a webhook
      tags:
        - Webhooks
  "/webhooks/{id}":
    delete:
      responses:
        "200":
          description: The webhook was deleted successfully
        "404":
          $ref: "#/components/responses/bad-webhook-id"
      summary: Delete a webhook
      tags:
        - Webhooks
    get:
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
          description: The properties of a specific webhook
        "400":
          $ref: "#/components/responses/bad-webhook-url"
        "404":
          $ref: "#/components/responses/bad-webhook-id"
      summary: Read a webhook
      tags:
        - Webhooks
    parameters:
      - description: The `id` of the webhook
        in: path
        name: id
        required: true
        schema:
          type: string
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookEntry"
        description: |
          Contains the new property values for the webhook
        required: true
      responses:
        "200":
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Webhook"
          description: The properties of the updated webhook
        "404":
          $ref: "#/components/responses/bad-webhook-id"
      summary: Update a webhook
      tags:
        - Webhooks
components:
  responses:
    bad-request:
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
      description: Bad Request. The content or structure of your submission, or a parameter, was found to be invalid.
    bad-webhook-id:
      content:
        application/json:
          examples:
            response:
              value:
                detail: |
                  Webhook with id '1' does not exist
                status: 404
                title: Not Found
                type: https://developer.bulksms.com/json/v1/errors/#not-found
          schema:
            $ref: "#/components/schemas/Error"
      description: A webhook with the given id does not exit
    bad-webhook-url:
      content:
        application/json:
          examples:
            response:
              value:
                detail: |
                  Invoking the Webhook URL caused an error: 403 - Forbidden
                status: 400
                title: Bad Request
                type: https://developer.bulksms.com/json/v1/errors/#bad-request
          schema:
            $ref: "#/components/schemas/Error"
      description: The url given for the webhook is not callable
    credits:
      content:
        application/json:
          examples:
            response:
              value:
                status: 403
                title: Insufficient Credits
                type: https://developer.bulksms.com/json/v1/errors#insufficient-credits
          schema:
            $ref: "#/components/schemas/Error"
      description: Forbidden.  Inspect the body of the response for further details - for example, you may have insufficient credits remaining
  schemas:
    BlockedNumber:
      properties:
        id:
          description: A unique identifier that is assigned when the BlockedNumber is created.
          example: 234
          format: int32
          type: number
        phoneNumber:
          allOf:
            - $ref: "#/components/schemas/PhoneNumber"
      required:
        - id
        - phoneNumber
      type: object
    Error:
      description: See the [errors page](errors/) for more detail on what kind of errors you can get.
      properties:
        detail:
          description: More information about why the error occurred.
          type: string
        status:
          description: The HTTP status code
          format: int32
          type: integer
        title:
          description: A short description of the type
          type: string
        type:
          description: A URL to one of the [error types](errors/).
          type: string
      required:
        - type
        - title
        - status
      type: object
    Message:
      properties:
        body:
          description: The content of the message
        creditCost:
          description: The cost of the message (in credits).   Note that this field does not have a value in the submission response.
          format: float
          type: number
        encoding:
          description: The type of the content.  See the `encoding` field for more information.
          enum:
            - TEXT
            - UNICODE
            - BINARY
          type: string
        from:
          description: The address part of the sender id
          type: string
        id:
          description: A unique identifier that is assigned when the message is created.
          type: string
        messageClass:
          description: See the `messageClass` field for more information.
          format: int32
          type: integer
        numberOfParts:
          description: The number of parts.  If this is a concatenated message, the number of parts will be more than 1.  Note that this field does not have a value in the submission response.
          format: int32
          type: integer
        protocolId:
          description: See the `protocolId` field for more information.
          format: int32
          type: integer
        relatedSentMessageId:
          description: |
            This field has a value only if the type is RECEIVED.
            With SMS messages, it is not possible to link a reply directly with a specific sent message.  However, if you specified `REPLIABLE` in the `from` property, BulkSMS will link any reply to the most recent message sent to a given phone number.

            The `relatedSentMessageId` property keeps the information about this link.

            You can use this property to derive an implicit conversation from a set of messages.
              - If a received reply message has a `relatedSentMessageId`, you can use it to retrieve the last message that was sent before the reply was received.
              - If you have the `id` of the sent message and you want all the received messages that relate to it, you can use the List Related Messages Operation.
          type: string
        status:
          description: The status of the message
          properties:
            id:
              description: |
                A concatenated value A.B where A is the `status.type` and B is the `status.subtype`.  
                It there is no value for `subtype` then B takes string value `"null"` (e.g. `"SENT.null"`).   
              type: string
            subtype:
              description: |
                Has a value only if the `type` is FAILED.

                EXPIRED  Delivery failed because message expired before delivery was possible.

                HANDSET_ERROR  Delivery failed because of a problem related to the phone (e.g. message storage area full).

                BLOCKED  Your account has been blocked from sending to this phone (e.g. recipient replied STOP to block communication).

                NOT_SENT  Message delivery was not attempted (e.g. because we were not able to find a route for the supplied phone number).
              enum:
                - EXPIRED
                - HANDSET_ERROR
                - BLOCKED
                - NOT_SENT
              type: string
            type:
              description: |
                
                ACCEPTED  Message accepted for delivery. Only returned for initial message submissions.

                SCHEDULED  Message accepted for delivery at a later date. Only returned for initial message  submissions.

                SENT  Message has been relayed away from our systems.

                DELIVERED  Successfully delivered to phone.

                UNKNOWN  Message is in an unknown state.

                FAILED  Delivery failed.
              enum:
                - ACCEPTED
                - SCHEDULED
                - SENT
                - DELIVERED
                - UNKNOWN
                - FAILED
              type: string
          required:
            - id
            - type
          type: object
        submission:
          description: |
            Identifies the submission.
          properties:
            date:
              description: The date and time the submission was processed. If the `type` is RECEIVED, this field reflects the date and time the received message was processed.
              format: date-time
              type: string
            id:
              description: A unique identity shared by all messages that were created from the same submission. This field should be ignored if the `type` is not SENT.
              type: string
          required:
            - id
            - date
          type: object
        to:
          description: The phone number of the recipient
          type: string
        type:
          description: The message direction
          enum:
            - SENT
            - RECEIVED
          type: string
        userSuppliedId:
          description: |
            This is the value you supplied in the `userSuppliedId` field.
            Has a value only if the `type` is SENT.
          type: string
      required:
        - id
        - type
        - to
        - body
        - status
      type: object
    PhoneNumber:
      description: A phone number in E.164 format
      example: "44123456789"
      type: string
    PreSignInfo:
      properties:
        fetchUrl:
          description: The URL you use in your SMS text.  It is the file location.
          example: https://smsattach.it/bedhkd.pdf
          type: string
        fields:
          description: Name value objects to add to the headers of the PUT request.
          items:
            properties:
              name:
                description: The header name
                example: x-amz-acl
                type: string
              value:
                description: The header value
                example: public-read
                type: string
            type: object
          type: array
        putUrl:
          description: The address of the PUT request to upload the file.
          example: https://some.place/aethzd.pdf?Token=IQoJb3JpZ2luX2EP3
          type: string
      type: object
    PreSignRequest:
      properties:
        fileExtension:
          description: The extension of the file.  Usually related to the media type.
          example: pdf
          type: string
        mediaType:
          description: The media type of the file you would like to upload.  If you are not sure what value to use here, check out the standard [list of media types](https://www.iana.org/assignments/media-types/media-types.xhtml).
          example: application/pdf
          type: string
      type: object
    Profile:
      properties:
        commerce:
          properties:
            address:
              properties:
                city:
                  type: string
                country:
                  type: string
                postalCode:
                  type: string
                region:
                  type: string
                street:
                  items:
                    type: string
                  type: array
              type: object
            bankPaymentReference:
              type: string
          type: object
        company:
          properties:
            name:
              type: string
            taxReference:
              type: string
          type: object
        created:
          format: date-time
          type: string
        credits:
          properties:
            balance:
              format: float
              type: number
            isTransferAllowed:
              type: boolean
            limit:
              format: int32
              type: integer
          type: object
        id:
          type: string
        originAddresses:
          properties:
            allowed:
              items:
                type: string
              type: array
            isFullControlAllowed:
              type: boolean
          type: object
        quota:
          properties:
            remaining:
              description: The number of messages you can still send today.
              format: int32
              type: integer
            size:
              description: The setting that limits the number of messages you can send in a day.
              format: int32
              type: integer
          required:
            - size
            - remaining
          type: object
        username:
          type: string
      required:
        - id
        - username
        - created
        - credits
        - quota
      type: object
    SubmissionEntry:
      description: An object that you use when posting messages.
      properties:
        body:
          description: |
            The message content as described in the `encoding`. If the `encoding` is BINARY, the body must contain only hexadecimal digits where one byte is represented as two digits. For example, if you want to send two bytes '0x05' and '0x1F', the message body must contain the text '051F'.

            The message content can also contain templates, read the [body templates section](#tag/Message) for more information.
          example: Hi there!
          type: string
        deliveryReports:
          description: |-
            The type of delivery reports to request from the delivering network.
            The default value  is `ALL`. Please note that not all networks support delivery reports.
            ALL. All possible delivery reports
            ERRORS. Only error delivery reports
            NONE. No delivery reports
          enum:
            - ALL
            - ERRORS
            - NONE
          type: string
        encoding:
          description: |
            Describes the content of the message body.

            Typically this is TEXT, which is the default if no value is provided.

            If you need to send characters that are not covered by the [GSM 03.38](https://en.wikipedia.org/wiki/GSM_03.38) character set you will need to specify UNICODE.

            If you want to send a sequence of bytes, you must use BINARY.

            You can also or use the `auto-unicode` parameter of the Send Messages Operation.   

            If you supply the value of `TEXT` while `auto-unicode` is `true` then your message may be converted to `UNICODE`.

            If you supply a value other than `TEXT` for this property while `auto-unicode` is `true` then no automatic conversion will take place.
          enum:
            - TEXT
            - UNICODE
            - BINARY
          type: string
        from:
          description: |
            Identifies the sender.

            Instead of a structured object, you can supply a string value here. 
            If you do this, the `type` of the sender is derived to be either INTERNATIONAL or ALPHANUMERIC.  If the value does not begin with a `+` and it contains at least one character that is not a digit, the type is detected as ALPHANUMERIC. Otherwise, the type is detected as INTERNATIONAL.
          properties:
            address:
              description: |
                The address of the sender id.

                The validation for this field depends on the value of the `type`.
                INTERNATIONAL can start with `+`. It has a maximum length of 15 digits, and has to be longer than 6 digits.
                ALPHANUMERIC has a maximum length of 11 characters.
                SHORTCODE has a maximum length of 6 digits.
                REPLIABLE should not specify a value here.
              example: "1111111"
              type: string
            type:
              description: |
                The type of the sender id.

                If you want BulkSMS to collect replies to this message on your behalf, specify the type as REPLIABLE.  If the recipient is in a country where BulkSMS does not have a local reply number, the reply may incur costs that are more expensive than sending a local SMS in that country.
                If you operate a service from a shortcode in a locale that allows messaging from such a shortcode, you can specify SHORTCODE for the type.
              enum:
                - INTERNATIONAL
                - ALPHANUMERIC
                - SHORTCODE
                - REPLIABLE
              type: string
          required:
            - type
          type: object
        longMessageMaxParts:
          description: |
            The maximum number of message parts that can be used for a [concatenated message](https://en.wikipedia.org/wiki/Concatenated_SMS).
            The default is `3`.
          example: 99
          format: int32
          type: integer
        messageClass:
          description: |
            The class of the message, as specified by §4 of the GSM 03.38 specification.

            You can provide either an integer value, or a mnemonic string.

            The default value is SIM_SPECIFIC.
            Numeric values are
            | Name | Value|
            |------|------|
            | FLASH_SMS | 0      |
            | ME_SPECIFIC | 1    |
            | SIM_SPECIFIC | 2   |
            | TE_SPECIFIC | 3   |
          enum:
            - FLASH_SMS
            - ME_SPECIFIC
            - SIM_SPECIFIC
            - TE_SPECIFIC
          type: string
        protocolId:
          description: |
            The TP-PID value from GSM 03.40[.750] §9.2.3.9.

            You can provide either an integer value, or a mnemonic string.

            If unspecified, this property defaults to `0`, representing the IMPLICIT value.
            Numeric values are listed below
            | Name | Value|
            |----- |------|
            | IMPLICIT              | 00 |
            | SHORT_MESSAGE_TYPE_0  | 64 |
            | REPLACE_MESSAGE_1     | 65 |
            | REPLACE_MESSAGE_2     | 66 |
            | REPLACE_MESSAGE_3     | 67 |
            | REPLACE_MESSAGE_4     | 68 |
            | REPLACE_MESSAGE_5     | 69 |
            | REPLACE_MESSAGE_6     | 70 |
            | REPLACE_MESSAGE_7     | 71 |
            | RETURN_CALL           | 95 |
            | ME_DOWNLOAD           | 125 |
            | ME_DEPERSONALIZE      | 126 |
            | SIM_DOWNLOAD          | 127 |
          enum:
            - IMPLICIT
            - SHORT_MESSAGE_TYPE_0
            - REPLACE_MESSAGE_1
            - REPLACE_MESSAGE_2
            - REPLACE_MESSAGE_3
            - REPLACE_MESSAGE_4
            - REPLACE_MESSAGE_5
            - REPLACE_MESSAGE_6
            - REPLACE_MESSAGE_7
            - RETURN_CALL
            - ME_DOWNLOAD
            - ME_DEPERSONALIZE
            - SIM_DOWNLOAD
          type: string
        routingGroup:
          description: |
            Allows you to choose routing. The default is STANDARD.
          enum:
            - ECONOMY
            - STANDARD
            - PREMIUM
          type: string
        to:
          description: |
            Identifies the recipients

            Instead of an array of structured objects, you can also provide a single object, a simple string or an array of strings.
            If you supply a string, the `type` is taken as INTERNATIONAL.
          items:
            example:
              address: "1111111"
              fields:
                - Jack
                - $200.00
              type: INTERNATIONAL
            properties:
              address:
                description: The phone number of the recipient.  It must be supplied if the `type` is INTERNATIONAL
                type: string
              fields:
                description: |
                  Custom fields that can be used in the message body. A value can be given if the `type` is INTERNATIONAL

                  Read the [body templates section](#tag/Message) for more information.
                items:
                  type: string
                type: array
              id:
                description: The id of a group in your phonebook.  A value can be given if the `type` is GROUP.
                type: string
              name:
                description: The name of a group in your phonebook. A value can be given if the `type` is GROUP.
                type: string
              type:
                description: Type of the recipient. The default value is INTERNATIONAL.
                enum:
                  - INTERNATIONAL
                  - GROUP
                type: string
            type: object
          type: array
        userSuppliedId:
          description: |
            Correlate the messages created from this submission to your data.

            The value can contain no more than 20 characters.
          example: submission-12765
          type: string
      required:
        - to
        - body
      type: object
    TransferEntry:
      properties:
        commentOnFrom:
          description: |
            An optional note that will be shown on the credit history of your account.
            The maximum length of the comment is 100.
          example: Tranfer to Bobby
          type: string
        commentOnTo:
          description: |
            An optional note that will be shown on the credit history of the recipient's account.
            The maximum length of the comment is 100.
          example: Tranfer from Danny
          type: string
        credits:
          description: |
            The amount of credits to transfer.
          example: 2345
          type: number
        toUserId:
          description: |
            The numeric user ID of the account that will receive the credits.
            The ID must match the username.
          example: 2345
          type: number
        toUsername:
          description: |
            The username of the account that will receive the credits.
          example: roboto
          type: string
      required:
        - toUsername
        - toUserId
        - credits
      type: object
    Webhook:
      properties:
        active:
          example: true
          type: boolean
        contactEmailAddress:
          example: tech_team@example.com
          type: string
        id:
          example: 234
          type: number
        name:
          example: My MT Webhook
          type: string
        onWebApp:
          example: true
          type: boolean
        triggerScope:
          example: SENT
          type: string
        url:
          example: https://www.example.com
          type: string
      type: object
    WebhookEntry:
      properties:
        active:
          description: |
            Indicates whether you want the webhook activated.

            If the value is `true`, the webhook at the given `url` will be invoked with an empty array (`[]`) as part of the validation process.
            If the webhook responds with a `2xx` status code, the submission is accepted; if not the webhook is not created (or updated).

            If the value is `false` the webhook will be inactive, and it will not be invoked when messages are `SENT` or `RECEIVED`.

            The default value is `true`.
          example: true
          type: boolean
        contactEmailAddress:
          description: |
            The email address to which emails will be sent if there are problem with invoking the webhook.

            The value must be a valid email address.
            If this value is `null`, no email will be sent.

            It is `null` by default.
          example: tech_team@example.com
          type: string
        invokeOption:
          description: |
            Specifies how to invoke your webhook.

            If the value is `ONE` the array POSTed to your webhook will contain no more than a single message.  Use this option if your webhook logic is unable to handle more than one messages at a time.

            If the value is `MANY` the array POSTed to your webhook can contain up to 10 messages.  This is the recommended option.  The number of calls made to your webhook would be less and this will speed up your total processing time.
            If your webhook fails for an invoke that has more than one message, each message in the array will automatically be retried one at a time. 

            This value defaults to `ONE` - but it is recommended that you set this property to `MANY`.
          enum:
            - ONE
            - MANY
          example: MANY
          type: string
        name:
          description: |
            A text identifier for the webhook.
            More than one webhook cannot have the same name.
          example: My MT Webhook
          type: string
        onWebApp:
          description: |
            Indicates whether you want to show this webhook on the Web App.

            Webhooks shown there can be updated by the user that use the public Web site.

            The default value is `true`.
          example: true
          type: boolean
        triggerScope:
          description: |
            Specifies when the webhook will be triggered.  

            Please note the values are case sensitive.

            If the value is `SENT`, the webhook will be called when a status update becomes available for a message you sent (i.e. a mobile terminating (MT) message).

            If the value is `RECEIVED`, the webhook will be called when a message is received (i.e. a mobile originating (MO) message).

            Note that this field forces you to create two separate webhook entries if you want to collect all messages.  However,  you can use the same `url` for both webhooks if you want.
          enum:
            - SENT
            - RECEIVED
          example: SENT
          type: string
        url:
          description: |
            The location of the webhook.

            In addition to being a [valid URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax), the url must also start with `http` or `https`.
          example: https://www.example.com
          type: string
      required:
        - name
        - url
        - triggerScope
      type: object
  securitySchemes:
    basicAuth:
      description: |
        The API uses HTTP Basic Auth for authentication.

        You are requested to preemptively provide the `Authorization` header in your requests and not wait until the server has provided a `401 Unauthorized` response.

        Doing so will reduce the number of requests required to achieve your goal, which will improve overall performance.

        You authenticate using either the username you supplied when you registered with [BulkSMS](https://www.bulksms.com) or with an _API Token_. API tokens can be created by logging into your account and visiting _Settings &gt; Developer Settings &gt; API Tokens_.

        __Important:__
        - Where possible, use an API Token instead of the username and password when writing software against the API.

        Whether you use a username or an API Token, the values must be [Base64 encoded](https://en.wikipedia.org/wiki/Base64) before using it in the header.
        For example, if the username is `Aladdin` and the password is `OpenSesame`, the unencoded header value is `Aladdin:OpenSesame`.  After encoding, the full header becomes

        ```
        Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
        ```
        When using an API token, the value to be encoded will be `<token-id>:<token-secret>`.  These values _before Base64 encoding_ look something like this

        `
        BBDE1B476E03498AA768F66A286AABDC-01-B:9jSbVDK20!MXdfRGiIIFu#ffUE8*S
        `
      scheme: basic
      type: http
