Quickstart
Three steps from signup to a delivered message.
Step 1
Create an API key
Sign up free and generate a key from your account settings. Every new account gets 5 credits to test with.
Step 2
POST to /send
Send JSON with a to number in international format and your message body. You get a message_id back straight away.
Step 3
Listen for webhooks
Point Texto at your HTTPS endpoint to receive signed delivery receipts and inbound replies as they happen.
SDKs and packages for message sending
Texto is a plain JSON REST API, so there's no proprietary SDK to install or keep up to date. Drop the snippet for your stack into a small client class and you're done — install, send and error handling for Node.js, PHP, Python and .NET below.
Send an SMS with Node.js
No package required — Node 18+ ships with fetch
# Node 18 and above has fetch built in. # On older versions, add a fetch polyfill: npm install node-fetch
Send a message
// texto.js
const TEXTO_API_KEY = process.env.TEXTO_API_KEY;
export async function sendSms({ to, message, from, campaign }) {
const response = await fetch("https://api.texto.com.au/send", {
method: "POST",
headers: {
Authorization: `Bearer ${TEXTO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ to, message, from, campaign }),
});
const data = await response.json();
if (!response.ok) {
throw new Error(`Texto ${response.status}: ${data.error ?? "request failed"}`);
}
return data;
}
const result = await sendSms({
to: "+61412345678",
message: "Your order has shipped.",
campaign: "order-updates",
});
console.log(result.message_id, result.credits_remaining);Handle errors
try {
await sendSms({ to: "+61412345678", message: "Hello" });
} catch (err) {
// 401 invalid key · 402 out of credits · 422 invalid number · 429 rate limited
console.error(err.message);
}Send an SMS with PHP
Recommended: Guzzle via Composer
composer require guzzlehttp/guzzle
Send a message
<?php
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
$client = new Client(['base_uri' => 'https://api.texto.com.au/']);
function sendSms(Client $client, string $to, string $message, ?string $campaign = null): array
{
$response = $client->post('send', [
'headers' => [
'Authorization' => 'Bearer ' . getenv('TEXTO_API_KEY'),
'Content-Type' => 'application/json',
],
'json' => array_filter([
'to' => $to,
'message' => $message,
'campaign' => $campaign,
]),
]);
return json_decode((string) $response->getBody(), true);
}
$result = sendSms($client, '+61412345678', 'Your order has shipped.', 'order-updates');
echo $result['message_id'], ' ', $result['credits_remaining'];Handle errors
try {
$result = sendSms($client, '+61412345678', 'Hello');
} catch (RequestException $e) {
// 401 invalid key · 402 out of credits · 422 invalid number · 429 rate limited
$status = $e->getResponse()?->getStatusCode();
$body = (string) $e->getResponse()?->getBody();
error_log("Texto {$status}: {$body}");
}Send an SMS with Python
Recommended: requests
pip install requests
Send a message
# texto.py
import os
import requests
BASE_URL = "https://api.texto.com.au"
API_KEY = os.environ["TEXTO_API_KEY"]
def send_sms(to: str, message: str, campaign: str | None = None) -> dict:
response = requests.post(
f"{BASE_URL}/send",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={k: v for k, v in {
"to": to,
"message": message,
"campaign": campaign,
}.items() if v is not None},
timeout=15,
)
response.raise_for_status()
return response.json()
result = send_sms("+61412345678", "Your order has shipped.", "order-updates")
print(result["message_id"], result["credits_remaining"])Handle errors
from requests import HTTPError
try:
send_sms("+61412345678", "Hello")
except HTTPError as err:
# 401 invalid key · 402 out of credits · 422 invalid number · 429 rate limited
print(err.response.status_code, err.response.text)Send an SMS with .NET
No package required — HttpClient is built in
# System.Net.Http and System.Text.Json ship with .NET.
# Register a typed client in Program.cs:
builder.Services.AddHttpClient("texto", c =>
c.BaseAddress = new Uri("https://api.texto.com.au/"));Send a message
using System.Net.Http.Json;
using System.Net.Http.Headers;
public record SendSmsRequest(string To, string Message, string? Campaign = null);
public record SendSmsResponse(string message_id, int credits_used, int credits_remaining);
public class TextoClient(HttpClient http, string apiKey)
{
public async Task<SendSmsResponse> SendSmsAsync(SendSmsRequest request)
{
http.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
var response = await http.PostAsJsonAsync("send", new
{
to = request.To,
message = request.Message,
campaign = request.Campaign,
});
response.EnsureSuccessStatusCode();
return (await response.Content.ReadFromJsonAsync<SendSmsResponse>())!;
}
}
var result = await client.SendSmsAsync(
new SendSmsRequest("+61412345678", "Your order has shipped.", "order-updates"));
Console.WriteLine($"{result.message_id} {result.credits_remaining}");Handle errors
try
{
await client.SendSmsAsync(new SendSmsRequest("+61412345678", "Hello"));
}
catch (HttpRequestException ex)
{
// 401 invalid key · 402 out of credits · 422 invalid number · 429 rate limited
Console.Error.WriteLine($"Texto {(int?)ex.StatusCode}: {ex.Message}");
}Machine-readable specs
Prefer to generate your own client? Every endpoint is published in four spec formats, so you can point your existing toolchain at Texto and go.
Everything else you'll need
REST API reference
Sending, tracking and reports, and the full account management surface.
Read moreDelivery receipt webhooks
HMAC-SHA256 signed, retried and idempotent delivery status callbacks.
Read moreInbound message webhooks
Receive replies and opt-outs on your own HTTPS endpoint.
Read moreMCP server
Send SMS from Claude, ChatGPT, Cursor, Windsurf, Gemini, Lovable and any MCP client.
Read moreAccount management
Create sub-accounts, allocate credits and provision keys for your own customers.
Read moreSMS glossary
Segments, GSM-7, E.164, DLRs and every other term you'll hit in the docs.
Read moreShip your first message today
Free account, 5 credits to test with, and a key you can generate in under a minute. 3¢ per SMS to Australia after that — no contracts, no platform fee.