Contact lists
Recipient lists stored on the TextMe side. Each contact can carry up to six dynamic fields — arbitrary values such as a first name or a city — which a send can merge into the message body.
Six operations cover the lifecycle: create, delete, add numbers, remove numbers, read all, read one.
POST https://my.textme.co.il/apiThese operations report row-level failures separately
A malformed phone number does not fail the call. The list is still created or updated, status comes back 0, and the rejected rows are listed in errors. Reading status alone will make you think every contact was stored. See Partial success.
newCL Create contact lists
Creates one or more lists, optionally populated in the same call.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
newCL | 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. | ✔️ |
cl | object | The details of a contact list to create. Repeatable — several lists per call. | ✔️ |
cl.name | string | The list's name. | ✔️ |
destinations | object | Contains all the numbers being added to this list. | ✔️ |
destination | object | One contact. Repeatable. | ✔️ |
phone | int | The contact's number, formatted 5xxxxxxx or 05xxxxxxx. | ✔️ |
df1 … df6 | string | Dynamic fields for this contact — up to six per row. | ➖ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<newCL>
<user>
<username>xxxxxx</username>
</user>
<cl>
<name>name1</name>
<destinations>
<destination>
<phone>055XXXXXXX</phone>
<df1>Israel</df1>
<df2>Israeli</df2>
<df3>Haifa</df3>
</destination>
<destination>
<phone>55XXXXXXX</phone>
</destination>
</destinations>
</cl>
<cl>
<name>name2</name>
<destinations>
<destination>
<phone>055XXXXXXX</phone>
</destination>
</destinations>
</cl>
</newCL>{
"newCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"newCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}'// 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({
newCL: {
user: {
username: 'xxxxxx',
},
cl: [
{
name: 'name1',
destinations: {
destination: [
{
phone: '055XXXXXXX',
df1: 'Israel',
df2: 'Israeli',
df3: 'Haifa',
},
{
phone: '55XXXXXXX',
},
],
},
},
{
name: 'name2',
destinations: {
destination: [
{
phone: '055XXXXXXX',
},
],
},
},
],
},
}),
})
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' => [
'newCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'name' => 'name1',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
'df1' => 'Israel',
'df2' => 'Israeli',
'df3' => 'Haifa',
],
[
'phone' => '55XXXXXXX',
],
],
],
],
[
'name' => 'name2',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
],
],
],
],
],
],
],
]);
$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', [
'newCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'name' => 'name1',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
'df1' => 'Israel',
'df2' => 'Israeli',
'df3' => 'Haifa',
],
[
'phone' => '55XXXXXXX',
],
],
],
],
[
'name' => 'name2',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
],
],
],
],
],
],
])
->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={
"newCL": {
"user": {
"username": "xxxxxx",
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa",
},
{
"phone": "55XXXXXXX",
},
],
},
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
},
],
},
},
],
},
},
)
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{
"newCL": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"cl": []any{
map[string]any{
"name": "name1",
"destinations": map[string]any{
"destination": []any{
map[string]any{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa",
},
map[string]any{
"phone": "55XXXXXXX",
},
},
},
},
map[string]any{
"name": "name2",
"destinations": map[string]any{
"destination": []any{
map[string]any{
"phone": "055XXXXXXX",
},
},
},
},
},
},
})
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 TextMeClCreate {
public static void main(String[] args) throws Exception {
String body = """
{
"newCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}
""";
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 = """
{
"newCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}
""";
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({
"newCL" => {
"user" => {
"username" => "xxxxxx",
},
"cl" => [
{
"name" => "name1",
"destinations" => {
"destination" => [
{
"phone" => "055XXXXXXX",
"df1" => "Israel",
"df2" => "Israeli",
"df3" => "Haifa",
},
{
"phone" => "55XXXXXXX",
},
],
},
},
{
"name" => "name2",
"destinations" => {
"destination" => [
{
"phone" => "055XXXXXXX",
},
],
},
},
],
},
})
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!({
"newCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"name": "name1",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"name": "name2",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}))
.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"?>
<newCL>
<status>0</status>
<message>conact list successfully created</message>
<errors>
<error>The phone is too long or too short or contain characters and therefore not added</error>
</errors>
<identifiers>
<identifier>17419</identifier>
</identifiers>
</newCL>{
"status": 0,
"message": "conact list successfully created",
"errors": [
"The phone is too long or too short or contain characters and therefore not added"
],
"identifiers": "17419"
}| Field | Type | Description |
|---|---|---|
status | int | 0 — the lists were created. |
message | string | conact list successfully created — the typo is in the API. |
errors | array | Rows that were rejected. Empty or absent when every contact stored. |
identifiers | string / array | The id of each list created. This is the cl_id you send messages to. |
Capture identifiers
It is the only place the new list's id appears. Lose it and you have to go looking with getCL.
Errors
| Status | When |
|---|---|
2 | cl, name or destinations is missing. |
9 | A destination is malformed — though note this usually arrives as an errors entry, not a failed call. |
511 | The account is not entitled to this operation. |
removeCL Delete contact lists
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
removeCL | 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. | ✔️ |
cl | object | Contains the identifiers you want to remove. | ✔️ |
id | string | The id of a contact list to remove. Repeatable. | ✔️ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<removeCL>
<user>
<username>xxxxxx</username>
</user>
<cl>
<id>21518</id>
<id>21500</id>
</cl>
</removeCL>{
"removeCL": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": [
"21518",
"21500"
]
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"removeCL": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": [
"21518",
"21500"
]
}
}
}'// 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({
removeCL: {
user: {
username: 'xxxxxx',
},
cl: {
id: [
'21518',
'21500',
],
},
},
}),
})
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' => [
'removeCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
'id' => [
'21518',
'21500',
],
],
],
],
]);
$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', [
'removeCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
'id' => [
'21518',
'21500',
],
],
],
])
->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={
"removeCL": {
"user": {
"username": "xxxxxx",
},
"cl": {
"id": [
"21518",
"21500",
],
},
},
},
)
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{
"removeCL": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"cl": map[string]any{
"id": []any{
"21518",
"21500",
},
},
},
})
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 TextMeClRemove {
public static void main(String[] args) throws Exception {
String body = """
{
"removeCL": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": [
"21518",
"21500"
]
}
}
}
""";
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 = """
{
"removeCL": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": [
"21518",
"21500"
]
}
}
}
""";
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({
"removeCL" => {
"user" => {
"username" => "xxxxxx",
},
"cl" => {
"id" => [
"21518",
"21500",
],
},
},
})
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!({
"removeCL": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": [
"21518",
"21500"
]
}
}
}))
.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"?>
<removeCL>
<status>0</status>
<message>contact list successfully removed</message>
<errors>
<error>contact list id: 21500 does not exist and therefore not removed</error>
</errors>
</removeCL>{
"status": 0,
"message": "conact lists successfully removed",
"errors": [
"contact list id: 21500 does not exist and therefore not removed"
]
}Ids that do not exist are reported in errors while the rest are removed — the call still answers 0.
Errors
| Status | When |
|---|---|
2 | cl or id is missing. |
988 | Contact list are entered not exist. |
511 | The account is not entitled to this operation. |
addNumCL Add numbers to a list
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
addNumCL | 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. | ✔️ |
cl | object | The list to update. Repeatable — several lists per call. | ✔️ |
cl.id | int | The id of the contact list to update. | ✔️ |
destinations | object | Contains all the numbers to add to this list. | ✔️ |
destination | object | One contact. Repeatable. | ✔️ |
phone | int | The contact's number, formatted 5xxxxxxx or 05xxxxxxx. | ✔️ |
df1 … df6 | string | Dynamic fields for this contact in this list. | ➖ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<addNumCL>
<user>
<username>xxxxxx</username>
</user>
<cl>
<id>21518</id>
<destinations>
<destination>
<phone>055XXXXXXX</phone>
<df1>Israel</df1>
<df2>Israeli</df2>
<df3>Haifa</df3>
</destination>
<destination>
<phone>55XXXXXXX</phone>
</destination>
</destinations>
</cl>
<cl>
<id>21500</id>
<destinations>
<destination>
<phone>055XXXXXXX</phone>
</destination>
</destinations>
</cl>
</addNumCL>{
"addNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"addNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}'// 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({
addNumCL: {
user: {
username: 'xxxxxx',
},
cl: [
{
id: '21518',
destinations: {
destination: [
{
phone: '055XXXXXXX',
df1: 'Israel',
df2: 'Israeli',
df3: 'Haifa',
},
{
phone: '55XXXXXXX',
},
],
},
},
{
id: '21500',
destinations: {
destination: [
{
phone: '055XXXXXXX',
},
],
},
},
],
},
}),
})
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' => [
'addNumCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'id' => '21518',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
'df1' => 'Israel',
'df2' => 'Israeli',
'df3' => 'Haifa',
],
[
'phone' => '55XXXXXXX',
],
],
],
],
[
'id' => '21500',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
],
],
],
],
],
],
],
]);
$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', [
'addNumCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'id' => '21518',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
'df1' => 'Israel',
'df2' => 'Israeli',
'df3' => 'Haifa',
],
[
'phone' => '55XXXXXXX',
],
],
],
],
[
'id' => '21500',
'destinations' => [
'destination' => [
[
'phone' => '055XXXXXXX',
],
],
],
],
],
],
])
->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={
"addNumCL": {
"user": {
"username": "xxxxxx",
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa",
},
{
"phone": "55XXXXXXX",
},
],
},
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
},
],
},
},
],
},
},
)
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{
"addNumCL": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"cl": []any{
map[string]any{
"id": "21518",
"destinations": map[string]any{
"destination": []any{
map[string]any{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa",
},
map[string]any{
"phone": "55XXXXXXX",
},
},
},
},
map[string]any{
"id": "21500",
"destinations": map[string]any{
"destination": []any{
map[string]any{
"phone": "055XXXXXXX",
},
},
},
},
},
},
})
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 TextMeClAddNumbers {
public static void main(String[] args) throws Exception {
String body = """
{
"addNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}
""";
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 = """
{
"addNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}
""";
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({
"addNumCL" => {
"user" => {
"username" => "xxxxxx",
},
"cl" => [
{
"id" => "21518",
"destinations" => {
"destination" => [
{
"phone" => "055XXXXXXX",
"df1" => "Israel",
"df2" => "Israeli",
"df3" => "Haifa",
},
{
"phone" => "55XXXXXXX",
},
],
},
},
{
"id" => "21500",
"destinations" => {
"destination" => [
{
"phone" => "055XXXXXXX",
},
],
},
},
],
},
})
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!({
"addNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX",
"df1": "Israel",
"df2": "Israeli",
"df3": "Haifa"
},
{
"phone": "55XXXXXXX"
}
]
}
},
{
"id": "21500",
"destinations": {
"destination": [
{
"phone": "055XXXXXXX"
}
]
}
}
]
}
}))
.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"?>
<sms>
<status>0</status>
<message>The phone numbers have been added successfully</message>
<errors>
<error>The phone 055XXXXXXX is already on the contact list and therefore not added</error>
</errors>
</sms>{
"status": 0,
"message": "The phone numbers have been added successfully",
"errors": [
"The phone 05XXXXXXXX is already on the contact list and therefore not added"
]
}Numbers already on the list are reported in errors and skipped — adding is effectively idempotent per number.
Errors
| Status | When |
|---|---|
2 | cl, id or destinations is missing. |
988 | The contact list does not exist. |
511 | The account is not entitled to this operation. |
rmNumCL Remove numbers from a list
Note the shape difference: here destinations holds phone elements directly, with no destination wrapper.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
rmNumCL | 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. | ✔️ |
cl | object | The list to update. Repeatable. | ✔️ |
cl.id | int | The id of the contact list to update. | ✔️ |
destinations | object | Contains the numbers to remove from this list. | ✔️ |
phone | int | A number to remove, formatted 5xxxxxxx or 05xxxxxxx. Repeatable. | ✔️ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<rmNumCL>
<user>
<username>xxxxxx</username>
</user>
<cl>
<id>21518</id>
<destinations>
<phone>055XXXXXXX</phone>
</destinations>
</cl>
<cl>
<id>21500</id>
<destinations>
<phone>055XXXXXXX</phone>
<phone>55XXXXXXX</phone>
</destinations>
</cl>
</rmNumCL>{
"rmNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX"
}
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX"
]
}
}
]
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"rmNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX"
}
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX"
]
}
}
]
}
}'// 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({
rmNumCL: {
user: {
username: 'xxxxxx',
},
cl: [
{
id: '21518',
destinations: {
phone: '055XXXXXXX',
},
},
{
id: '21500',
destinations: {
phone: [
'055XXXXXXX',
'55XXXXXXX',
],
},
},
],
},
}),
})
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' => [
'rmNumCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'id' => '21518',
'destinations' => [
'phone' => '055XXXXXXX',
],
],
[
'id' => '21500',
'destinations' => [
'phone' => [
'055XXXXXXX',
'55XXXXXXX',
],
],
],
],
],
],
]);
$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', [
'rmNumCL' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
[
'id' => '21518',
'destinations' => [
'phone' => '055XXXXXXX',
],
],
[
'id' => '21500',
'destinations' => [
'phone' => [
'055XXXXXXX',
'55XXXXXXX',
],
],
],
],
],
])
->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={
"rmNumCL": {
"user": {
"username": "xxxxxx",
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX",
},
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX",
],
},
},
],
},
},
)
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{
"rmNumCL": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"cl": []any{
map[string]any{
"id": "21518",
"destinations": map[string]any{
"phone": "055XXXXXXX",
},
},
map[string]any{
"id": "21500",
"destinations": map[string]any{
"phone": []any{
"055XXXXXXX",
"55XXXXXXX",
},
},
},
},
},
})
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 TextMeClRemoveNumbers {
public static void main(String[] args) throws Exception {
String body = """
{
"rmNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX"
}
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX"
]
}
}
]
}
}
""";
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 = """
{
"rmNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX"
}
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX"
]
}
}
]
}
}
""";
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({
"rmNumCL" => {
"user" => {
"username" => "xxxxxx",
},
"cl" => [
{
"id" => "21518",
"destinations" => {
"phone" => "055XXXXXXX",
},
},
{
"id" => "21500",
"destinations" => {
"phone" => [
"055XXXXXXX",
"55XXXXXXX",
],
},
},
],
},
})
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!({
"rmNumCL": {
"user": {
"username": "xxxxxx"
},
"cl": [
{
"id": "21518",
"destinations": {
"phone": "055XXXXXXX"
}
},
{
"id": "21500",
"destinations": {
"phone": [
"055XXXXXXX",
"55XXXXXXX"
]
}
}
]
}
}))
.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"?>
<rmNumCL>
<status>0</status>
<message>Successfully deleted phone numbers</message>
<errors>
<error>contact list id: 21500 does not exist and therefore not removed</error>
</errors>
</rmNumCL>{
"status": 0,
"message": "Successfully deleted phone numbers",
"errors": [
"contact list id: 21500 does not exist and therefore not removed"
]
}Errors
| Status | When |
|---|---|
2 | cl, id or destinations is missing. |
988 | The contact list does not exist. |
511 | The account is not entitled to this operation. |
getCL List every contact list
Returns every list on the account, including empty ones, as a flat sequence of rows.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
getCL | 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. | ✔️ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<getCL>
<user>
<username>xxxxxx</username>
</user>
</getCL>{
"getCL": {
"user": {
"username": "xxxxxx"
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"getCL": {
"user": {
"username": "xxxxxx"
}
}
}'// 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({
getCL: {
user: {
username: 'xxxxxx',
},
},
}),
})
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' => [
'getCL' => [
'user' => [
'username' => 'xxxxxx',
],
],
],
]);
$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', [
'getCL' => [
'user' => [
'username' => 'xxxxxx',
],
],
])
->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={
"getCL": {
"user": {
"username": "xxxxxx",
},
},
},
)
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{
"getCL": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
},
})
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 TextMeClGetAll {
public static void main(String[] args) throws Exception {
String body = """
{
"getCL": {
"user": {
"username": "xxxxxx"
}
}
}
""";
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 = """
{
"getCL": {
"user": {
"username": "xxxxxx"
}
}
}
""";
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({
"getCL" => {
"user" => {
"username" => "xxxxxx",
},
},
})
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!({
"getCL": {
"user": {
"username": "xxxxxx"
}
}
}))
.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"?>
<getCL>
<status>0</status>
<message></message>
<contact_lists>
<contact_list>
<cl_id>21518</cl_id>
<phone>55XXXXXXX</phone>
<name>name1</name>
</contact_list>
<contact_list>
<cl_id>21500</cl_id>
<phone>055XXXXXXX</phone>
<name>name2</name>
</contact_list>
</contact_lists>
</getCL>{
"status": 0,
"message": "",
"contact_lists": [
{
"cl_id": "21518",
"phone": "55XXXXXXX",
"name": "name1"
},
{
"cl_id": "21500",
"phone": "555XXXXXX",
"name": "name2"
}
]
}| Field | Type | Description |
|---|---|---|
contact_lists | array | One row per contact, not per list. |
contact_lists[].cl_id | string | The list this contact belongs to. |
contact_lists[].phone | string | The contact's number. |
contact_lists[].name | string | The list's name, repeated on every row. |
The response is rows, not lists
A list of three contacts produces three rows carrying the same cl_id and name. Group by cl_id to reconstruct the lists — and expect the response to grow with the number of contacts, not the number of lists.
Errors
| Status | When |
|---|---|
3, 10, 11 | Token invalid, expired, or belonging to another username. |
511 | The account is not entitled to this operation. |
getCLbyID Read one contact list
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
getCLbyID | 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. | ✔️ |
cl | object | Contains contact list elements. | ✔️ |
id | int | The id of the contact list you want. | ✔️ |
Request example
<?xml version="1.0" encoding="UTF-8"?>
<getCLbyID>
<user>
<username>xxxxxx</username>
</user>
<cl>
<id>21518</id>
</cl>
</getCLbyID>{
"getCLbyID": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": "21518"
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"getCLbyID": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": "21518"
}
}
}'// 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({
getCLbyID: {
user: {
username: 'xxxxxx',
},
cl: {
id: '21518',
},
},
}),
})
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' => [
'getCLbyID' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
'id' => '21518',
],
],
],
]);
$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', [
'getCLbyID' => [
'user' => [
'username' => 'xxxxxx',
],
'cl' => [
'id' => '21518',
],
],
])
->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={
"getCLbyID": {
"user": {
"username": "xxxxxx",
},
"cl": {
"id": "21518",
},
},
},
)
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{
"getCLbyID": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"cl": map[string]any{
"id": "21518",
},
},
})
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 TextMeClGetById {
public static void main(String[] args) throws Exception {
String body = """
{
"getCLbyID": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": "21518"
}
}
}
""";
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 = """
{
"getCLbyID": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": "21518"
}
}
}
""";
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({
"getCLbyID" => {
"user" => {
"username" => "xxxxxx",
},
"cl" => {
"id" => "21518",
},
},
})
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!({
"getCLbyID": {
"user": {
"username": "xxxxxx"
},
"cl": {
"id": "21518"
}
}
}))
.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"?>
<getCLbyID>
<status>0</status>
<message></message>
<contact_lists>
<contact_list>
<phone>55XXXXXXX</phone>
<name>name1</name>
</contact_list>
</contact_lists>
</getCLbyID>{
"status": 0,
"message": "",
"contact_lists": [
{
"cl_id": "21518",
"phone": "55XXXXXXX",
"name": "name1"
},
{
"cl_id": "21518",
"phone": "555XXXXXX",
"name": "name1"
}
]
}Same row shape as getCL, narrowed to one list.
Errors
| Status | When |
|---|---|
2 | cl or id is missing. |
988 | The contact list does not exist. |
511 | The account is not entitled to this operation. |
Field notes
Dynamic fields
Each contact can carry six values, df1 through df6. In a message body they are referenced positionally:
Hello [DYNAMIC_FIELD1] [DYNAMIC_FIELD2], your parcel is on its way to [DYNAMIC_FIELD3].With df1 = Israel, df2 = Israeli, df3 = Haifa, that arrives as Hello Israel Israeli, your parcel is on its way to Haifa.
To use them, sms needs add_dynamic set to 1, exactly one cl_id, and no individual phone elements — the merge values have to come from a single list. Full walkthrough in Work with contact lists.
Dynamic fields belong to the membership, not the contact
The same number on two lists can carry different values in each, because df1–df6 are stored per row. That is useful — a customer can be "Israel" on your Hebrew list and "Mr Israeli" on your formal one — and it is also a trap: updating a value means updating it on every list the number appears on.
Reading is expensive, writing is cheap
getCL returns one row per contact across the whole account. On an account with large lists that is a lot of payload for what is usually a small question. Cache the cl_id you get from newCL at creation time and you will rarely need to call it.
There is no update operation
To change a contact's dynamic fields, remove the number with rmNumCL and add it again with addNumCL carrying the new values. Adding a number that is already present is rejected per row rather than treated as an update.

