UNPKG

49.7 kBJSONView Raw
1{"openapi":"3.0.0","info":{"description":"## Overview\n\nThe 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.\n\nThe 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.\n\n[Click here](/) to go to the main BulkSMS developer site.\n\nIn 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.\n\nProbably the most simple example\n\n```\n{\n \"to\": \"+27001234567\",\n \"body\": \"Hello World!\"\n}\n```\n\n\nYou can send unicode automatically using the `auto-unicode` query parameter. \nAlternatively, you can specify UNICODE in the request body. Here is an example that sets the `encoding` explicitly\n\n```\n{\n \"to\": \"+27001234567\",\n \"body\": \"Dobrá práce! Jak se máš?\",\n \"encoding\": \"UNICODE\"\n}\n```\n\nYou can also specify a from number\n\n```\n{\n \"from\": \"+27007654321\",\n \"to\": \"+27001234567\",\n \"body\": \"Hello World!\"\n}\n```\n\nSimilar to above, but repliable\n\n```\n{\n \"from\": { \"type\": \"REPLIABLE\" },\n \"to\": \"+27001234567\",\n \"body\": \"Hello World!\"\n}\n```\n\nA message to a group called Everyone\n\n```\n{\n \"to\": { \"type\": \"GROUP\", \"name\": \"Everyone\" },\n \"body\": \"Hello World!\"\n}\n```\n\nA message to multiple recipients\n\n```\n{\n \"to\": [\"+27001234567\", \"+27002345678\", \"+27003456789\"],\n \"body\": \"Happy Holidays!\"\n}\n```\n\nSending more than one message in the same request\n\n```\n[\n {\n \"to\": \"+27001234567\",\n \"body\": \"Hello World!\"\n },\n {\n \"to\": \"+27002345678\",\n \"body\": \"Hello Universe!\"\n }\n]\n```\n\n**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.\n\n### HTTP Content Type\n\nAll 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`.\n\n### JSON Formatting\n\nYou 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.\n\nGood 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.\n\nSee the [JSON specification](https://tools.ietf.org/html/rfc4627) for further information.\n\n### Date Formatting\n\nDates are formatted according to ISO-8601, such as `1970-01-01T10:00:00+01:00` for 1st January 1970, 10AM UTC+1.\n\nSee the [Wikipedia ISO 8601 reference](https://en.wikipedia.org/wiki/ISO_8601) for further information.\n\nSpecifically, 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.\n\nThe format we look for is `yyyy-MM-ddThh:mm:ss[Z|[+-]hh:mm]`\n\nExamples of valid date/times are`2011-12-31T12:00:00Z` `2011-12-31T12:00:00+02:00`\n\n### Entity Format Modifications\n\nIt is expected that over time some changes will be made to the request and response formats of various methods available in the API.\nWhere possible, these will be implemented in a backwards compatible way.\nTo make this possible you are required to ignore unknown properties.\nThis enables the addition of information in response documents while maintaining compatibility with older clients.\n\n### Optional Request Entity Properties\n\nThere are many instances where requests can be made without having to specify every single property allowable in the request format.\nAny such optional properties are noted as such in the documentation and their default value is noted.\n","title":"BulkSMS JSON","version":"1.0.0","x-apisguru-categories":["telecom"],"x-logo":{"url":"https://www.bulksms.com/img/homegraphics/bulksms-logo.png"},"x-origin":[{"format":"swagger","url":"http://developer.bulksms.com/json/v1/swagger.yaml","version":"2.0"}],"x-providerName":"bulksms.com"},"security":[{"basicAuth":[]}],"tags":[{"name":"Message","x-displayName":"Messages"},{"name":"Profile","x-displayName":"Profile"}],"paths":{"/messages":{"get":{"description":"Retrieve the messages you have sent or received.\n\nAll the parameters are optional. If a value is not supplied for `filter`, the messages are not filtered.\n\nMessages 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.\nFor a numeric filter field, you can also use the less than operator (`<`).\n\nIf 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).\n\nFor 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\n```\ntype%3DSENT&submission.id%3D1-00000000000522347562\n```\nBecause `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.\n\nUsing the previous example to illustrate; after encoding and encasing it, the clauses are transformed into a request that looks like this\n```\nGET /v1/messages?filter=type%3DSENT%26submission.id%3D1-00000000000522347562\n```\nIf 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.\n\nThe table below lists the fields available for filtering\n\n| Field | Type | Values | Note and example |\n|-------|------|--------------------|------|\n| 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` |\n| type | String | SENT, RECEIVED | SENT are Mobile Terminating (MT) SMSs; RECEIVED are Mobile Originating (MO) SMSs.<br/>`filter=type%3DSENT` |\n| submission.id | String | | `filter=submission.id%3D1-00000000000522347562` |\n| status.type | String | ACCEPTED, SCHEDULED, SENT, DELIVERED, FAILED | See the message `status.type` field for more information. <br/>`filter=status.type%3DDELIVERED` |\n| status.id| String | | See the message `status.id` field for more information. `filter=status.id%3DFAILED.EXPIRED`|\n| 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` |\n| 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` |\n","parameters":[{"description":"The maximum number of messages that are returned. The default is 1000.\nThe 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":{"type":"number","format":"int"}},{"description":"See the message filtering for more information.","in":"query","name":"filter","schema":{"type":"string"}},{"description":"The default value is DESCENDING\n\nIf the `sortOrder` is DESCENDING, the newest messages be first in the result. ASCENDING places the oldest messages on top of the response.\n","in":"query","name":"sortOrder","schema":{"type":"string","enum":["ASCENDING"]}}],"responses":{"200":{"description":"Contains the requested array of messages","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"}}}},"400":{"$ref":"#/components/responses/bad-request"}},"security":[{"basicAuth":[]}],"summary":"Retrieve Messages","tags":["Message"],"x-code-samples":[{"lang":"C#","source":"using System;\nusing System.IO;\nusing System.Net;\n\n class MainClass\n {\n\n public static void Main(string[] args)\n {\n /** \n Note in the query string \n we have a filter to get only the \n SENT messages\n */\n string myURI = \"https://api.bulksms.com/v1/messages?filter=type%3DSENT\";\n string myUsername = \"username\";\n string myPassword = \"yourPassword\";\n var request = WebRequest.Create(myURI);\n request.Credentials = new NetworkCredential(myUsername, myPassword);\n request.PreAuthenticate = true;\n request.Method = \"GET\";\n request.ContentType = \"application/json\";\n try\n {\n // make the call to the API\n var response = request.GetResponse();\n\n // read the response and print it to the console\n var reader = new StreamReader(response.GetResponseStream());\n Console.WriteLine(reader.ReadToEnd());\n\n } catch (WebException ex) {\n // show the general message\n Console.WriteLine(\"An error occurred:\" + ex.Message);\n\n // print the detail that come with the HTTP error \n var reader = new StreamReader(ex.Response.GetResponseStream());\n Console.WriteLine(\"Error details:\" + reader.ReadToEnd());\n }\n }\n}\n"}]},"post":{"description":"Send messages to one or more recipients.\n\n#### Repliability\n\nWhen a sent message is _repliable_, the BulkSMS system can process an SMS response sent by your recipient.\n\nThe message sent by your customer is called a mobile originating (MO) message and would be available under `RECEIVED` messages. \nYou can obtain a list of MOs using the [retrieve messages API call](#tag/Message%2Fpaths%2F~1messages%2Fget).\nIn 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)).\n\nIf you use a specific _sender id_ in the `from` property of the send message, the message will not be repliable.\nIf you want a message to be repliable, you need to specify `REPLIABLE` in the `from.type` property.\n\nIf you do not set the `from` property, your account settings are considered to determine whether or not the message is repliable.\nIf the _default repliable_ setting on your account is _yes_ then the message will be repliable. \nIf this setting is _no_, the message will not be repliable.\n\n\n#### Body templates\n\nWhen sending a message you can use template fields to customise the message text.\n\n*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. \n\nFor 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 \n\n```\nGood morning {F0######}, your balance is {F1######}\n```\n\nIn 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.\n\nThe data fields are provided in the property named `fields` in the `to` element. Here is a complete example of how this might look\n\n```\n{\n \"body\": \"Good morning {F0######}, your balance is {F1######}\",\n \"to\": [\n {\"address\": \"27456789\",\"fields\": [\"Harry\", \"$1345.23\"] },\n {\"address\": \"27456785\",\"fields\": [\"Sally\", \"$2345.58\"] }\n ]\n}\n```\n\nIf 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. \n\n```\n{\n \"body\": \"Hi {fn######} {sn######}, have a great day!\",\n \"to\": [\n {\"address\": \"27456789\" },\n {\"address\": \"27456785\" }\n ]\n}\n```\n","parameters":[{"description":"Safeguards against the possibility of sending the same messages more than once.\n\nIf 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.\n","in":"query","name":"deduplication-id","schema":{"type":"integer","format":"int32"}},{"description":"Specifies how to deal with message text that contains characters not present in the GSM 03.38 character set.\n\nMessages 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 shorter, and could require extra SMSs to transmit). If the value is `false`, then non-GSM 03.38 characters will be replaced by the `?` character.\n","in":"query","name":"auto-unicode","schema":{"type":"boolean","default":false}},{"description":"Allows you to send a message in the future.\n\nAn example value is `2019-02-18T13:00:00+02:00`. It encodes to `2019-02-18T13%3A00%3A00%2B02%3A00`.\nCredits are deducted from your account immediately. Once submitted, scheduled messages cannot be changed or cancelled.\nThe date can be a maximum of two years in the future. If the value is in the past, the message will be sent immediately.\nThe 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.\nIf 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.\n","in":"query","name":"schedule-date","schema":{"type":"string","format":"date-time"}},{"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.\n\nThe value of this field is ignored if the `schedule-date` is not provided.\nA value that is longer than 256 characters is truncated.\n","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.\n\nOne `SubmissionEntry` can produce many messages, and your request may contain multiple such entries.\n","required":true},"responses":{"201":{"description":"An array of the messages that were created from the request","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"}}}},"400":{"$ref":"#/components/responses/bad-request"},"403":{"$ref":"#/components/responses/credits"}},"security":[{"basicAuth":[]}],"summary":"Send Messages","tags":["Message"],"x-code-samples":[{"lang":"PHP","source":"<?\n// Your PHP installation needs cUrl support, which not all PHP installations\n// include by default.\n// To run under docker:\n// docker run -v $PWD:/code php:7.3.2-alpine php /code/code_sample.php\n\n$username = 'your_username';\n$password = 'your_password';\n$messages = array(\n array('to'=>'+1233454567', 'body'=>'Hello World!'),\n array('to'=>'+1233454568', 'body'=>'Hello World!')\n);\n\n$result = send_message( json_encode($messages), 'https://api.bulksms.com/v1/messages', $username, $password );\n\nif ($result['http_status'] != 201) {\n print \"Error sending: \" . ($result['error'] ? $result['error'] : \"HTTP status \".$result['http_status'].\"; Response was \" .$result['server_response']);\n} else {\n print \"Response \" . $result['server_response'];\n // Use json_decode($result['server_response']) to work with the response further\n}\n\nfunction send_message ( $post_body, $url, $username, $password) {\n $ch = curl_init( );\n $headers = array(\n 'Content-Type:application/json',\n 'Authorization:Basic '. base64_encode(\"$username:$password\")\n );\n curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);\n curl_setopt ( $ch, CURLOPT_URL, $url );\n curl_setopt ( $ch, CURLOPT_POST, 1 );\n curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );\n curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_body );\n // Allow cUrl functions 20 seconds to execute\n curl_setopt ( $ch, CURLOPT_TIMEOUT, 20 );\n // Wait 10 seconds while trying to connect\n curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 10 );\n $output = array();\n $output['server_response'] = curl_exec( $ch );\n $curl_info = curl_getinfo( $ch );\n $output['http_status'] = $curl_info[ 'http_code' ];\n $output['error'] = curl_error($ch);\n curl_close( $ch );\n return $output;\n} \n?> \n"},{"lang":"C#","source":"using System;\nusing System.IO;\nusing System.Net;\nusing System.Text;\n\nclass MainClass\n{\n public static void Main(string[] args)\n {\n // This URL is used for sending messages\n string myURI = \"https://api.bulksms.com/v1/messages\";\n\n // change these values to match your own account\n string myUsername = \"username\";\n string myPassword = \"password\";\n\n // the details of the message we want to send\n string myData = \"{to: \\\"1111111\\\", body:\\\"Hello Mr. Smith!\\\"}\";\n\n // build the request based on the supplied settings\n var request = WebRequest.Create(myURI);\n\n // supply the credentials\n request.Credentials = new NetworkCredential(myUsername, myPassword);\n request.PreAuthenticate = true;\n // we want to use HTTP POST\n request.Method = \"POST\";\n // for this API, the type must always be JSON\n request.ContentType = \"application/json\";\n\n // Here we use Unicode encoding, but ASCIIEncoding would also work\n var encoding = new UnicodeEncoding();\n var encodedData = encoding.GetBytes(myData);\n\n // Write the data to the request stream\n var stream = request.GetRequestStream();\n stream.Write(encodedData, 0, encodedData.Length);\n stream.Close();\n\n // try ... catch to handle errors nicely\n try\n {\n // make the call to the API\n var response = request.GetResponse();\n\n // read the response and print it to the console\n var reader = new StreamReader(response.GetResponseStream());\n Console.WriteLine(reader.ReadToEnd());\n }\n catch (WebException ex)\n {\n // show the general message\n Console.WriteLine(\"An error occurred:\" + ex.Message);\n\n // print the detail that comes with the error\n var reader = new StreamReader(ex.Response.GetResponseStream());\n Console.WriteLine(\"Error details:\" + reader.ReadToEnd());\n }\n }\n}\n"},{"lang":"Java","source":"import java.net.*;\nimport java.util.Base64;\nimport java.io.*;\n\npublic class MainClass {\n\n static public void main(String[] args) throws Exception {\n\n // This URL is used for sending messages\n String myURI = \"https://api.bulksms.com/v1/messages\";\n\n // change these values to match your own account\n String myUsername = \"username\";\n String myPassword = \"password\";\n\n // the details of the message we want to send\n String myData = \"{to: \\\"1111111\\\", encoding: \\\"UNICODE\\\", body: \\\"Dobrá práce! Jak se máš?\\\"}\";\n\n // if your message does not contain unicode, the \"encoding\" is not required:\n // String myData = \"{to: \\\"1111111\\\", body: \\\"Hello Mr. Smith!\\\"}\";\n\n // build the request based on the supplied settings\n URL url = new URL(myURI);\n HttpURLConnection request = (HttpURLConnection) url.openConnection();\n request.setDoOutput(true);\n\n // supply the credentials\n String authStr = myUsername + \":\" + myPassword;\n String authEncoded = Base64.getEncoder().encodeToString(authStr.getBytes());\n request.setRequestProperty(\"Authorization\", \"Basic \" + authEncoded);\n\n // we want to use HTTP POST\n request.setRequestMethod(\"POST\");\n request.setRequestProperty( \"Content-Type\", \"application/json\");\n\n // write the data to the request\n OutputStreamWriter out = new OutputStreamWriter(request.getOutputStream());\n out.write(myData);\n out.close();\n\n // try ... catch to handle errors nicely\n try {\n // make the call to the API\n InputStream response = request.getInputStream();\n BufferedReader in = new BufferedReader(new InputStreamReader(response));\n String replyText;\n while ((replyText = in.readLine()) != null) {\n System.out.println(replyText);\n }\n in.close();\n } catch (IOException ex) {\n System.out.println(\"An error occurred:\" + ex.getMessage());\n BufferedReader in = new BufferedReader(new InputStreamReader(request.getErrorStream()));\n // print the detail that comes with the error\n String replyText;\n while ((replyText = in.readLine()) != null) {\n System.out.println(replyText);\n }\n in.close();\n }\n request.disconnect();\n }\n}\n"}]}},"/messages/send":{"get":{"description":"A really simple interface for people who require a GET mechanism to submit a message.\n\nThe URI is interpreted as UTF-8.\n\n__Note__ BulkSMS recommends that you use the more flexible Send Messages Operation when submitting SMS messages from your application.\n\nHere is an example of a GET\n```http\nGET /v1/messages/send?to=%2b270000000&body=Hello%20World\n```\n\nYou can also use the same parameters to POST form encoded fields to `/messages`.\nHere is an example of a POST\n```http\nPOST /v1/messages\nContent-Type: application/x-www-form-urlencoded\n\nto=%2b27000000000&body=Hello+World\n```\n","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":{"type":"integer","format":"int-32"}}],"responses":{"201":{"description":"An array of messages","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"}}}},"400":{"$ref":"#/components/responses/bad-request"},"403":{"$ref":"#/components/responses/credits"}},"security":[{"basicAuth":[]}],"summary":"Send message using GET","tags":["Message"]}},"/messages/{id}":{"get":{"description":"Get a the message by `id`.\n```http\nGET /v1/messages/4023457654\n```\n","parameters":[{"description":"The `id` of the message you want to retrieve","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The message detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"$ref":"#/components/responses/bad-request"},"404":{"description":"A [not-found error](errors/#not-found) if the message cannot be found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"summary":"Show Message","tags":["Message"]}},"/messages/{id}/relatedReceivedMessages":{"get":{"description":"Get the messages related to a sent message identified by `id`.\n\nFor more information how this work, see the `relatedSentMessageId` field in the message.\n","parameters":[{"description":"The `id` of the sent message","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"An array of related messages. If the `id` is not a sent message, the array will be empty.","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Message"},"type":"array"}}}},"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":{"description":"A Profile object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Profile"}}}}},"security":[{"basicAuth":[]}],"summary":"Get profile","tags":["Profile"]}},"/webhooks":{"get":{"description":"Contains a list of your webhooks","responses":{"200":{"description":"Array of Webhooks","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/Webhook"},"type":"array"}}}}},"security":[{"basicAuth":[]}],"summary":"List webhooks","tags":["Webhooks"]},"post":{"description":"A webhook is an URL that you can register if you want the BulkSMS system to notify you about your messages.\nYou can create multiple webhooks, and each one will be called.\nIf you want to be notified of `SENT` messages and `RECEIVED` messages you need to create two webhooks.\n\n__Important:__ The Webhooks methods do not work with an API Token, a username and password is required.\n\n### Implementing your webhook\n\nWhen you implement your webhook, there are a few rules to be aware of:\n- 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).\n- When you register or update your webhook, the URL will be tested by invoking it with an empty array (`[]`).\n- 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.\n- 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.\n- The webhook is expected to comply with good practices with regard to the status code it responds with.\n - 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.\n - 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.\n - 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).\n- Your webhook has to respond within `30` seconds. If no response is given in this time, the invocation will be retried.\n- It is good practise to add a secret to your URL in order to make it more secure. Here is an example:\n`https://www.example.com/hook.php?secret=pass763265word`\n- You can also use a non-standard port if necessary, for example: `https://www.example.com:8321/hook.php?secret=pass763265word`\n\n\n### The retry process\n\nThe process the BulkSMS systems follow to handle retries is roughly the following:\n- The first retry is scheduled for 90 seconds into the future.\n- After the first retry, subsequent failures will have longer delays, following this sequence - 3 minutes, 6 minutes, 12 minutes, 24 minutes, 48 minutes, 96 minutes, 3 hours, 6 hours, 12 hours, 24 hours.\n- When a failure occurs after the last delay in the sequence, the message is discarded.\n\n### Problem reports via email\n\nIt is strongly suggested that you provide an email address when you configure your webhook.\nAn email will be sent to this address to keep you in the loop whenever there are problems with your webhook.\nIn order to prevent your mailbox from being flooded, the BulksSMS system reports an observed error code no more than once in a 24 hour period.\n\nThe following emails can be expected\n - 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.\n - 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; or when the system decides to stop retrying.\n","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEntry"}}},"description":"Contains the property values for your new webhook\n","required":true},"responses":{"200":{"description":"Contains the webhook you created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"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":{"description":"The properties of a specific webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/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\n","required":true},"responses":{"200":{"description":"The properties of the updated webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"404":{"$ref":"#/components/responses/bad-webhook-id"}},"summary":"Update a webhook","tags":["Webhooks"]}}},"servers":[{"url":"https://api.bulksms.com/v1"}],"components":{"responses":{"bad-request":{"description":"Bad Request. The content or structure of your submission, or a parameter, was found to be invalid.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"bad-webhook-id":{"description":"A webhook with the given id does not exit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"response":{"value":{"detail":"Webhook with id '1' does not exist\n","status":404,"title":"Not Found","type":"https://developer.bulksms.com/json/v1/errors/#not-found"}}}}}},"bad-webhook-url":{"description":"The url given for the webhook is not callable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"response":{"value":{"detail":"Invoking the Webhook URL caused an error: 403 - Forbidden\n","status":400,"title":"Bad Request","type":"https://developer.bulksms.com/json/v1/errors/#bad-request"}}}}}},"credits":{"description":"Forbidden. Inspect the body of the response for further details - for example, you may have insufficient credits remaining","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"examples":{"response":{"value":{"status":403,"title":"Insufficient Credits","type":"https://developer.bulksms.com/json/v1/errors#insufficient-credits"}}}}}}},"securitySchemes":{"basicAuth":{"description":"The API uses HTTP Basic Auth for authentication.\n\nYou are requested to preemptively provide the `Authorization` header in your requests and not wait until the server has provided a `401 Unauthorized` response.\n\nDoing so will reduce the number of requests required to achieve your goal, which will improve overall performance.\n\nYou 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 _My Account | Advanced | API Tokens_.\n\n__Important:__\n- Access to the [Webhooks API](#tag/Webhooks) requires a username and password and does not work with an API Token.\n- Where possible, use an API Token instead of the username and password when writing software against the API.\n\nWhether 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.\nFor example, if the username is `Aladdin` and the password is `OpenSesame`, the unencoded header value is `Aladdin:OpenSesame`. After encoding, the full header becomes\n\n```\nAuthorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l\n```\nWhen using an API token, the value to be encoded will be `<token-id>:<token-secret>`. These values _before Base64 encoding_ look something like this\n\n`\nBBDE1B476E03498AA768F66A286AABDC-01-B:9jSbVDK20!MXdfRGiIIFu#ffUE8*S\n`\n","type":"http","scheme":"basic"}},"schemas":{"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.\nWith 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.\n\nThe `relatedSentMessageId` property keeps the information about this link.\n\nYou can use this property to derive an implicit conversation from a set of messages.\n - 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.\n - 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.\n","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`. \nIt there is no value for `subtype` then B takes string value `\"null\"` (e.g. `\"SENT.null\"`). \n","type":"string"},"subtype":{"description":"Has a value only if the `type` is FAILED.\n\nEXPIRED Delivery failed because message expired before delivery was possible.\n\nHANDSET_ERROR Delivery failed because of a problem related to the phone (e.g. message storage area full).\n\nBLOCKED Your account has been blocked from sending to this phone (e.g. recipient replied STOP to block communication).\n\nNOT_SENT Message delivery was not attempted (e.g. because we were not able to find a route for the supplied phone number).\n","enum":["EXPIRED","HANDSET_ERROR","BLOCKED","NOT_SENT"],"type":"string"},"type":{"description":"\nACCEPTED Message accepted for delivery. Only returned for initial message submissions.\n\nSCHEDULED Message accepted for delivery at a later date. Only returned for initial message submissions.\n\nSENT Message has been relayed away from our systems.\n\nDELIVERED Successfully delivered to phone.\n\nUNKNOWN Message is in an unknown state.\n\nFAILED Delivery failed.\n","enum":["ACCEPTED","SCHEDULED","SENT","DELIVERED","UNKNOWN","FAILED"],"type":"string"}},"required":["id","type"],"type":"object"},"submission":{"description":"Identifies the submission.\nThis field has a value only if the `type` is SENT.\n","properties":{"date":{"description":"The date and time the submission was processed.","format":"date-time","type":"string"},"id":{"description":"A unique identity shared by all messages that were created from the same submission.","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.\nHas a value only if the `type` is SENT.\n","type":"string"}},"required":["id","type","to","body","status"],"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'.\n\nThe message content can also contain templates, read the [body templates section](#tag/Message) for more information.\n","example":"Hi there!","type":"string"},"deliveryReports":{"description":"The type of delivery reports to request from the delivering network.\nThe default value is `ALL`. Please note that not all networks support delivery reports.\nALL. All possible delivery reports\nERRORS. Only error delivery reports\nNONE. No delivery reports","enum":["ALL","ERRORS","NONE"],"type":"string"},"encoding":{"description":"Describes the content of the message body.\n\nTypically this is TEXT, which is the default if no value is provided.\n\nIf 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 or use the `auto-unicode` parameter of the Send Messages Operation.\n\nIf you want to send a sequence of bytes, you must use BINARY.\n","enum":["TEXT","UNICODE","BINARY"],"type":"string"},"from":{"description":"Identifies the sender.\n\nInstead of a structured object, you can supply a string value here. \nIf 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.\n","properties":{"address":{"description":"The address of the sender id.\n\nThe validation for this field depends on the value of the `type`.\nINTERNATIONAL can start with `+`. It has a maximum length of 15 digits, and has to be longer than 6 digits.\nALPHANUMERIC has a maximum length of 11 characters.\nSHORTCODE has a maximum length of 6 digits.\nREPLIABLE should not specify a value here.\n","example":"1111111","type":"string"},"type":{"description":"The type of the sender id.\n\nIf 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.\nIf you operate a service from a shortcode in a locale that allows messaging from such a shortcode, you can specify SHORTCODE for the type.\n","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).\nThe default is `3`.\n","example":99,"format":"int32","type":"integer"},"messageClass":{"description":"The class of the message, as specified by §4 of the GSM 03.38 specification.\n\nYou can provide either an integer value, or a mnemonic string.\n\nThe default value is SIM_SPECIFIC.\nNumeric values are\n| Name | Value|\n|------|------|\n| FLASH_SMS | 0 |\n| ME_SPECIFIC | 1 |\n| SIM_SPECIFIC | 2 |\n| TE_SPECIFIC | 3 |\n","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.\n\nYou can provide either an integer value, or a mnemonic string.\n\nIf unspecified, this property defaults to `0`, representing the IMPLICIT value.\nNumeric values are listed below\n| Name | Value|\n|----- |------|\n| IMPLICIT | 00 |\n| SHORT_MESSAGE_TYPE_0 | 64 |\n| REPLACE_MESSAGE_1 | 65 |\n| REPLACE_MESSAGE_2 | 66 |\n| REPLACE_MESSAGE_3 | 67 |\n| REPLACE_MESSAGE_4 | 68 |\n| REPLACE_MESSAGE_5 | 69 |\n| REPLACE_MESSAGE_6 | 70 |\n| REPLACE_MESSAGE_7 | 71 |\n| RETURN_CALL | 95 |\n| ME_DOWNLOAD | 125 |\n| ME_DEPERSONALIZE | 126 |\n| SIM_DOWNLOAD | 127 |\n","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.\n","enum":["ECONOMY","STANDARD","PREMIUM"],"type":"string"},"to":{"description":"Identifies the recipients\n\nInstead of an array of structured objects, you can also provide a single object, a simple string or an array of strings.\nIf you supply a string, the `type` is taken as INTERNATIONAL.\n","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\n\nRead the [body templates section](#tag/Message) for more information.\n","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.\n\nThe value can contain no more than 20 characters.\n","example":"submission-12765","type":"string"}},"required":["to","body"],"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.\n\nIf the value is `true`, the webhook at the given `url` will be invoked with an empty array (`[]`) as part of the validation process.\nIf the webhook responds with a `2xx` status code, the submission is accepted; if not the webhook is not created (or updated).\n\nIf the value is `false` the webhook will be inactive, and it will not be invoked when messages are `SENT` or `RECEIVED`.\n\nThe default value is `true`.\n","example":true,"type":"boolean"},"contactEmailAddress":{"description":"The email address to which emails will be sent if there are problem with invoking the webhook.\n\nThe value must be a valid email address.\nIf this value is `null`, no email will be sent.\n\nIt is `null` by default.\n","example":"tech_team@example.com","type":"string"},"name":{"description":"A text identifier for the webhook.\nMore than one webhook cannot have the same name.\n","example":"My MT Webhook","type":"string"},"onWebApp":{"description":"Indicates whether you want to show this webhook on the Web App.\n\nWebhooks shown there can be updated by the user that use the public Web site.\n\nThe default value is `true`.\n","example":true,"type":"boolean"},"triggerScope":{"description":"Specifies when the webhook will be triggered. \n\nPlease note the values are case sensitive.\n\nIf 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).\nIf the value is `RECEIVED`, the webhook will be called when a message is received (i.e. a mobile originating (MO) message).\n\nNote 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.\n","enum":["SENT","RECEIVED"],"example":"SENT","type":"string"},"url":{"description":"The location of the webhook.\n\nIn addition to being a [valid URI](https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Syntax), the url must also start with `http` or `https`.\n","example":"https://www.example.com","type":"string"}},"required":["name","url","triggerScope"],"type":"object"}}}}
\No newline at end of file