Getting started
Textbelt is an SMS API that is built for developers who just want to send and receive SMS. Sending an SMS is a simple thing. Our goal is to provide an API that is correspondingly simple, without requiring account configuration, logins, or extra recurring billing.
The
https://textbelt.com/text
endpoint accepts a POST request with the following parameters:- phone: A phone number. If you're in the U.S. or Canada, you can just send a normal 10-digit phone number with area code. Outside the U.S., it is best to send the phone number in E.164 format with your country code.
- message: The content of your SMS.
- key: Your API key (use
textbelt
to send a free message). - sender: Optionally, the name of the business/organization you represent. If not set, this value will default to your account-wide semder name. See Compliance for more detail.
Every programming language has a way to send an HTTP POST request. Instead of installing a special Textbelt library, just send a POST request using your preferred method. Below are some examples in common languages.
Bash
Python
Ruby
Node
Javascript
PHP
C#
Java
Go
PSH
curl -X POST https://textbelt.com/text \
--data-urlencode phone='5555555555' \
--data-urlencode message='Hello world' \
-d key=textbelt
import requests
resp = requests.post('https://textbelt.com/text', {
'phone': '5555555555',
'message': 'Hello world',
'key': 'textbelt',
})
print(resp.json())
require 'net/http'
require 'uri'
uri = URI.parse("https://textbelt.com/text")
Net::HTTP.post_form(uri, {
:phone => '5555555555',
:message => 'Hello world',
:key => 'textbelt',
})
// Using request
const request = require('request');
request.post('https://textbelt.com/text', {
form: {
phone: '5555555555',
message: 'Hello world',
key: 'textbelt',
},
}, (err, httpResponse, body) => {
console.log(JSON.parse(body));
});
// Using axios
const axios = require('axios');
axios.post('https://textbelt.com/text', {
phone: '5555555555',
message: 'Hello world',
key: 'textbelt',
}).then(response => {
console.log(response.data);
})
fetch('https://textbelt.com/text', {
method: 'post',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phone: '5555555555',
message: 'Hello world',
key: 'textbelt',
}),
}).then(response => {
return response.json();
}).then(data => {
console.log(data);
});
$ch = curl_init('https://textbelt.com/text');
$data = array(
'phone' => '5555555555',
'message' => 'Hello world',
'key' => 'textbelt',
);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
using System;
using System.Collections.Specialized;
using System.Net;
using (WebClient client = new WebClient())
{
byte[] response = client.UploadValues("http://textbelt.com/text", new NameValueCollection() {
{ "phone", "5555555555" },
{ "message", "Hello world" },
{ "key", "textbelt" },
});
string result = System.Text.Encoding.UTF8.GetString(response);
}
final NameValuePair[] data = {
new BasicNameValuePair("phone", "5555555555"),
new BasicNameValuePair("message", "Hello world"),
new BasicNameValuePair("key", "textbelt")
};
HttpClient httpClient = HttpClients.createMinimal();
HttpPost httpPost = new HttpPost("https://textbelt.com/text");
httpPost.setEntity(new UrlEncodedFormEntity(Arrays.asList(data)));
HttpResponse httpResponse = httpClient.execute(httpPost);
String responseString = EntityUtils.toString(httpResponse.getEntity());
JSONObject response = new JSONObject(responseString);
import (
"net/http"
"net/url"
)
func main() {
values := url.Values{
"phone": {"5555555555"},
"message": {"Hello world"},
"key": {"textbelt"},
}
http.PostForm("https://textbelt.com/text", values)
}
$body = @{
"phone"="5555555555"
"message"="Hello World"
"key"="textbelt"
}
$submit = Invoke-WebRequest -Uri https://textbelt.com/text -Body $body -Method Post
Note: Regulations require that you state the name of your business/organization in SMS messages. If you are sending recurring SMS, opt-out language is required (e.g. "Reply STOP to opt-out". We automatically handle STOP replies).
The
/text
endpoint will respond with JSON:- success: Whether the message was successfully sent (true/false).
- quotaRemaining: The amount of credit remaining on your key.
- textId: The ID of the sent message, used for looking up its status. Only present when success=true. Use this to check SMS delivery status.
- error: A string describing the problem. Only present when success=false.
An example of a message successfully sent:
{"success": true, "quotaRemaining": 40, "textId": 12345}
Here's an example of when you've run out of quota:
{"success": false, "quotaRemaining": 0, "error": "Out of quota"}
Or when you're missing a required variable such as phone, message, or key:
{"success": false, "error": "Incomplete request"}
If you're getting the above message even though you're specifying the variable, you should make sure that you're sending the request correctly as an HTTP POST request.
If you want to validate your key without actually using your text quota, append "
_test
" to your key and you will receive a response from the /text
endpoint confirming that a text would send. However, credit will not be deducted from your account.U.S. phone numbers only: Textbelt lets you receive replies to SMS you've sent. Replies are sent by webhook, meaning you will have to set up an HTTP or HTTPS route on your website that will process inbound SMS.
Add a
replyWebhookUrl
parameter to your send message request. This is the same as the examples above, except it includes replyWebhookUrl. For example:curl -X POST https://textbelt.com/text \
--data-urlencode phone='5555555555' \
--data-urlencode message='Hello?' \
-d replyWebhookUrl='https://my.site/api/handleSmsReply' \
-d key=textbelt
This will send an SMS. If the recipient responds, Textbelt will send an HTTP POST request to the specified endpoint (in this case,
https://my.site/api/handleSmsReply
).The webhook payload is
application/json
encoded. Your server must interpret it like any other HTTP POST request with a JSON payload. The JSON payload contains the following:- textId: The ID of the original text that began the conversation.
- fromNumber: The phone number of the user that sent the reply (you can use this, for example, to send them a response depending on their reply).
- text: The content of their reply
Here's an example payload:
{
"textId": "123456",
"fromNumber": "+1555123456",
"text": "Here is my reply"
}
Note: SMS replies cannot be received on the free
textbelt
key.It is best practice to verify the incoming POST request to make sure it is not forged. The POST request contains a header
X-textbelt-signature
, which is an HMAC that authenticates the JSON payload using a SHA-256 hash function.The header
X-textbelt-timestamp
contains a UNIX timestamp (in seconds). You should ensure that this timestamp is not more than 15 minutes out of date.To verify that the request is valid, take the timestamp + raw JSON payload and sign it with your API key. The result should be equal to the signature.
For example, in Javascript:
const crypto = require("crypto");
function verify(apiKey, timestamp, requestSignature, requestPayload) {
const mySignature = crypto
.createHmac("sha256", apiKey)
.update(timestamp + requestPayload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(requestSignature),
Buffer.from(mySignature)
);
}
And in Python:
import hmac
import hashlib
def verify(api_key, timestamp, request_signature, request_payload):
my_signature = hmac.new(api_key.encode('utf-8'), (timestamp + request_payload).encode('utf-8'), hashlib.sha256).hexdigest()
return hmac.compare_digest(request_signature, my_signature)
Last modified 15d ago