Verified senders
The source on a send — the name or number the message appears to come from — has to be verified before it can be used. These two operations submit numbers for verification and list the ones already approved.
POST https://my.textme.co.il/apiSending from an unverified source fails with status 515.
verify_phone Submit numbers for verification
Starts verification for one or more numbers. Both mobile numbers and landlines are accepted, and each is verified differently — see the response note below.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
verify_phone | object | Contains all other elements. | ✔️ |
user | object | Contains the user element. | ✔️ |
username | string | The username of the account by which you are recognized in the system. | ✔️ |
phone | object | A number to use as an SMS source. Must be a legal mobile or landline number. Repeatable. | ✔️ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<verify_phone>
<user>
<username>Leeroy</username>
</user>
<phone>5xxxxxxxx</phone>
<phone>3xxxxxxx</phone>
</verify_phone>{
"verify_phone": {
"user": {
"username": "Leeroy"
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx"
]
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"verify_phone": {
"user": {
"username": "Leeroy"
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx"
]
}
}'// Node.js 18+ / browsers — no dependencies
const response = await fetch('https://my.textme.co.il/api', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TEXTME_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
verify_phone: {
user: {
username: 'Leeroy',
},
phone: [
'5xxxxxxxx',
'3xxxxxxx',
],
},
}),
})
const result = await response.json()
// Errors arrive as HTTP 200 too — the payload status is what counts
if (Number(result.status) !== 0) {
throw new Error(`TextMe ${result.status}: ${result.message}`)
}
console.log(result)<?php
// composer require guzzlehttp/guzzle
$client = new \GuzzleHttp\Client([
'headers' => [
'Authorization' => 'Bearer '.getenv('TEXTME_API_TOKEN'),
'Accept' => 'application/json',
],
]);
$response = $client->post('https://my.textme.co.il/api', [
'json' => [
'verify_phone' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => [
'5xxxxxxxx',
'3xxxxxxx',
],
],
],
]);
$result = json_decode($response->getBody()->getContents(), true);
// Errors arrive as HTTP 200 too — the payload status is what counts
if ((int) $result['status'] !== 0) {
throw new RuntimeException("TextMe {$result['status']}: {$result['message']}");
}
print_r($result);<?php
use Illuminate\Support\Facades\Http;
$result = Http::withToken(config('services.textme.token'))
->acceptJson()
->post('https://my.textme.co.il/api', [
'verify_phone' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => [
'5xxxxxxxx',
'3xxxxxxx',
],
],
])
->throw()
->json();
// Errors arrive as HTTP 200 too — the payload status is what counts
throw_if((int) $result['status'] !== 0, RuntimeException::class,
"TextMe {$result['status']}: {$result['message']}");
logger()->info('TextMe', $result);# pip install httpx
import os
import httpx
response = httpx.post(
"https://my.textme.co.il/api",
headers={"Authorization": f"Bearer {os.environ['TEXTME_API_TOKEN']}"},
json={
"verify_phone": {
"user": {
"username": "Leeroy",
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx",
],
},
},
)
response.raise_for_status()
result = response.json()
# Errors arrive as HTTP 200 too — the payload status is what counts
if int(result["status"]) != 0:
raise RuntimeError(f"TextMe {result['status']}: {result['message']}")
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
payload, _ := json.Marshal(map[string]any{
"verify_phone": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"phone": []any{
"5xxxxxxxx",
"3xxxxxxx",
},
},
})
req, _ := http.NewRequest("POST", "https://my.textme.co.il/api", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TEXTME_API_TOKEN"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var result struct {
Status json.Number `json:"status"`
Message string `json:"message"`
}
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
panic(err)
}
// Errors arrive as HTTP 200 too — the payload status is what counts
if result.Status.String() != "0" {
panic(fmt.Sprintf("TextMe %s: %s", result.Status, result.Message))
}
fmt.Println(result.Message)
}// Java 17+ — java.net.http, no dependencies (parse with Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TextMeVerifyPhone {
public static void main(String[] args) throws Exception {
String body = """
{
"verify_phone": {
"user": {
"username": "Leeroy"
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx"
]
}
}
""";
HttpRequest request = HttpRequest.newBuilder(URI.create("https://my.textme.co.il/api"))
.header("Authorization", "Bearer " + System.getenv("TEXTME_API_TOKEN"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// Errors arrive as HTTP 200 too — the payload status is what counts
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"verify_phone": {
"user": {
"username": "Leeroy"
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx"
]
}
}
""";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("TEXTME_API_TOKEN"));
var response = await http.PostAsync("https://my.textme.co.il/api",
new StringContent(payload, Encoding.UTF8, "application/json"));
var result = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
var status = result.GetProperty("status").ToString();
// Errors arrive as HTTP 200 too — the payload status is what counts
if (status != "0")
{
var message = result.GetProperty("message").ToString();
throw new Exception($"TextMe {status}: {message}");
}
Console.WriteLine(result);require "net/http"
require "json"
uri = URI("https://my.textme.co.il/api")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('TEXTME_API_TOKEN')}"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
"verify_phone" => {
"user" => {
"username" => "Leeroy",
},
"phone" => [
"5xxxxxxxx",
"3xxxxxxx",
],
},
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
# Errors arrive as HTTP 200 too — the payload status is what counts
raise "TextMe #{result['status']}: #{result['message']}" unless result["status"].to_i.zero?
pp result// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result: Value = reqwest::Client::new()
.post("https://my.textme.co.il/api")
.bearer_auth(std::env::var("TEXTME_API_TOKEN")?)
.json(&json!({
"verify_phone": {
"user": {
"username": "Leeroy"
},
"phone": [
"5xxxxxxxx",
"3xxxxxxx"
]
}
}))
.send()
.await?
.json()
.await?;
// Errors arrive as HTTP 200 too — the payload status is what counts
if result["status"] != 0 {
return Err(format!("TextMe {}: {}", result["status"], result["message"]).into());
}
println!("{result}");
Ok(())
}Response
<?xml version="1.0" encoding="utf-8"?>
<verify_phone>
<status>0</status>
<verify_message>verification link will be send to 5******** in order to complete the verification of 3******* call to 0552458888</verify_message>
</verify_phone>{
"status": 0,
"verify_message": "verification link will be send to 5******** in order to complete the verification of 3******* call to 0552458888"
}| Field | Type | Description |
|---|---|---|
status | int | 0 — the numbers were accepted for verification. |
verify_message | string | What happens next, per number. Note the field name: verify_message, not message. |
Accepted is not verified
status: 0 means verification has started. The verify_message explains what each number still needs:
- Mobile numbers receive a verification link by SMS, which someone must follow.
- Landlines cannot receive SMS, so verification is completed by calling the number given in the message.
Nothing can be sent from the number until that step is done. Confirm with getVerifiedPhones rather than assuming.
Errors
| Status | When |
|---|---|
510 | invalid verify_phone request: no phones to verify — no phone elements were supplied. |
9 | A number is too short or too long. |
511 | The account is not entitled to this operation. |
getVerifiedPhones List verified numbers
Returns the numbers already approved as senders, with when they were assigned and last updated.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
getVerifiedPhones | object | Contains all other elements. | ✔️ |
user | object | Contains the user element. | ✔️ |
username | string | The username of the account by which you are recognized in the system. | ✔️ |
is_subs | int | Set to 1 to include the verified numbers of your sub-accounts. Omit the field entirely to exclude them. | ➖ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<getVerifiedPhones>
<user>
<username>username</username>
</user>
<is_subs>1</is_subs>
</getVerifiedPhones>{
"getVerifiedPhones": {
"user": {
"username": "username"
},
"is_subs": "1"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"getVerifiedPhones": {
"user": {
"username": "username"
},
"is_subs": "1"
}
}'// Node.js 18+ / browsers — no dependencies
const response = await fetch('https://my.textme.co.il/api', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TEXTME_API_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
getVerifiedPhones: {
user: {
username: 'username',
},
is_subs: '1',
},
}),
})
const result = await response.json()
// Errors arrive as HTTP 200 too — the payload status is what counts
if (Number(result.status) !== 0) {
throw new Error(`TextMe ${result.status}: ${result.message}`)
}
console.log(result)<?php
// composer require guzzlehttp/guzzle
$client = new \GuzzleHttp\Client([
'headers' => [
'Authorization' => 'Bearer '.getenv('TEXTME_API_TOKEN'),
'Accept' => 'application/json',
],
]);
$response = $client->post('https://my.textme.co.il/api', [
'json' => [
'getVerifiedPhones' => [
'user' => [
'username' => 'username',
],
'is_subs' => '1',
],
],
]);
$result = json_decode($response->getBody()->getContents(), true);
// Errors arrive as HTTP 200 too — the payload status is what counts
if ((int) $result['status'] !== 0) {
throw new RuntimeException("TextMe {$result['status']}: {$result['message']}");
}
print_r($result);<?php
use Illuminate\Support\Facades\Http;
$result = Http::withToken(config('services.textme.token'))
->acceptJson()
->post('https://my.textme.co.il/api', [
'getVerifiedPhones' => [
'user' => [
'username' => 'username',
],
'is_subs' => '1',
],
])
->throw()
->json();
// Errors arrive as HTTP 200 too — the payload status is what counts
throw_if((int) $result['status'] !== 0, RuntimeException::class,
"TextMe {$result['status']}: {$result['message']}");
logger()->info('TextMe', $result);# pip install httpx
import os
import httpx
response = httpx.post(
"https://my.textme.co.il/api",
headers={"Authorization": f"Bearer {os.environ['TEXTME_API_TOKEN']}"},
json={
"getVerifiedPhones": {
"user": {
"username": "username",
},
"is_subs": "1",
},
},
)
response.raise_for_status()
result = response.json()
# Errors arrive as HTTP 200 too — the payload status is what counts
if int(result["status"]) != 0:
raise RuntimeError(f"TextMe {result['status']}: {result['message']}")
print(result)package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
func main() {
payload, _ := json.Marshal(map[string]any{
"getVerifiedPhones": map[string]any{
"user": map[string]any{
"username": "username",
},
"is_subs": "1",
},
})
req, _ := http.NewRequest("POST", "https://my.textme.co.il/api", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+os.Getenv("TEXTME_API_TOKEN"))
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
var result struct {
Status json.Number `json:"status"`
Message string `json:"message"`
}
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
panic(err)
}
// Errors arrive as HTTP 200 too — the payload status is what counts
if result.Status.String() != "0" {
panic(fmt.Sprintf("TextMe %s: %s", result.Status, result.Message))
}
fmt.Println(result.Message)
}// Java 17+ — java.net.http, no dependencies (parse with Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TextMeVerifiedPhones {
public static void main(String[] args) throws Exception {
String body = """
{
"getVerifiedPhones": {
"user": {
"username": "username"
},
"is_subs": "1"
}
}
""";
HttpRequest request = HttpRequest.newBuilder(URI.create("https://my.textme.co.il/api"))
.header("Authorization", "Bearer " + System.getenv("TEXTME_API_TOKEN"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
// Errors arrive as HTTP 200 too — the payload status is what counts
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"getVerifiedPhones": {
"user": {
"username": "username"
},
"is_subs": "1"
}
}
""";
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("TEXTME_API_TOKEN"));
var response = await http.PostAsync("https://my.textme.co.il/api",
new StringContent(payload, Encoding.UTF8, "application/json"));
var result = JsonDocument.Parse(await response.Content.ReadAsStringAsync()).RootElement;
var status = result.GetProperty("status").ToString();
// Errors arrive as HTTP 200 too — the payload status is what counts
if (status != "0")
{
var message = result.GetProperty("message").ToString();
throw new Exception($"TextMe {status}: {message}");
}
Console.WriteLine(result);require "net/http"
require "json"
uri = URI("https://my.textme.co.il/api")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch('TEXTME_API_TOKEN')}"
request["Content-Type"] = "application/json"
request.body = JSON.dump({
"getVerifiedPhones" => {
"user" => {
"username" => "username",
},
"is_subs" => "1",
},
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
# Errors arrive as HTTP 200 too — the payload status is what counts
raise "TextMe #{result['status']}: #{result['message']}" unless result["status"].to_i.zero?
pp result// [dependencies]
// reqwest = { version = "0.12", features = ["json"] }
// tokio = { version = "1", features = ["full"] }
// serde_json = "1"
use serde_json::{json, Value};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let result: Value = reqwest::Client::new()
.post("https://my.textme.co.il/api")
.bearer_auth(std::env::var("TEXTME_API_TOKEN")?)
.json(&json!({
"getVerifiedPhones": {
"user": {
"username": "username"
},
"is_subs": "1"
}
}))
.send()
.await?
.json()
.await?;
// Errors arrive as HTTP 200 too — the payload status is what counts
if result["status"] != 0 {
return Err(format!("TextMe {}: {}", result["status"], result["message"]).into());
}
println!("{result}");
Ok(())
}Response
<?xml version="1.0" encoding="UTF-8"?>
<getVerifiedPhones>
<status>0</status>
<message></message>
<verified_phones>
<verified_phone>
<PHONE>xxxxxxxxxx</PHONE>
<USER_ID>xxx</USER_ID>
<ASSIGNMENT_DATE>03/12/14 12:33</ASSIGNMENT_DATE>
<LAST_UPDATE>03/12/14 12:33</LAST_UPDATE>
</verified_phone>
</verified_phones>
</getVerifiedPhones>{
"status": 0,
"message": "",
"verified_phones": [
{
"PHONE": "xxxxxxxxxx",
"USER_ID": "XXXX",
"ASSIGNMENT_DATE": "03/12/14 12:33",
"LAST_UPDATE": "03/12/14 12:33"
}
]
}| Field | Type | Description |
|---|---|---|
verified_phones | array | One entry per verified number. |
PHONE | string | The verified number. |
USER_ID | string | The account it belongs to — useful when is_subs is 1. |
ASSIGNMENT_DATE | string | When it was verified, dd/mm/yy hh:mm. |
LAST_UPDATE | string | When the record last changed. |
Field names are upper case here
As with birthday campaigns, this response uses PHONE, USER_ID, ASSIGNMENT_DATE and LAST_UPDATE rather than the lower-case style used elsewhere.
Errors
| Status | When |
|---|---|
3, 10, 11 | Token invalid, expired, or belonging to another username. |
511 | The account is not entitled to this operation. |
Field notes
Numbers and alphanumeric senders
A source can be a number (0551234567) or a short alphanumeric name (DemoAPI) — up to 11 characters, letters and digits only, no +.
verify_phone covers the numeric case: it proves you control the line. Alphanumeric sender names are arranged with TextMe directly rather than through this operation, because there is no line to send a verification link to.
Verify before you need it
Verification involves a human — following a link, or placing a call — so it is not something to discover at deploy time. Call getVerifiedPhones as a startup check and fail loudly if the sender your configuration expects is missing. That turns a silent run of 515 failures into one clear error before any traffic moves.
Sub-accounts
A reseller's sub-accounts verify their own senders. is_subs: 1 gives the parent a single view across all of them, with USER_ID identifying the owner of each. Sub-account management is covered in Subscribers.
Voice calls do not use it
A TTS call always originates from a TextMe system number, whatever source says. Verification governs the SMS half of a send only.

