Skip to content

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.

http
POST https://my.textme.co.il/api

These 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

NameTypeDescriptionRequired
newCLobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️
clobjectThe details of a contact list to create. Repeatable — several lists per call.✔️
cl.namestringThe list's name.✔️
destinationsobjectContains all the numbers being added to this list.✔️
destinationobjectOne contact. Repeatable.✔️
phoneintThe contact's number, formatted 5xxxxxxx or 05xxxxxxx.✔️
df1df6stringDynamic fields for this contact — up to six per row.

Request example

xml
<?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>
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"
            }
          ]
        }
      }
    ]
  }
}
bash
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"
            }
          ]
        }
      }
    ]
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "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"
}
FieldTypeDescription
statusint0 — the lists were created.
messagestringconact list successfully created — the typo is in the API.
errorsarrayRows that were rejected. Empty or absent when every contact stored.
identifiersstring / arrayThe 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

StatusWhen
2cl, name or destinations is missing.
9A destination is malformed — though note this usually arrives as an errors entry, not a failed call.
511The account is not entitled to this operation.

removeCL Delete contact lists

Parameters

NameTypeDescriptionRequired
removeCLobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️
clobjectContains the identifiers you want to remove.✔️
idstringThe id of a contact list to remove. Repeatable.✔️

Request example

xml
<?xml version="1.0" encoding="UTF-8"?>
<removeCL>
    <user>
        <username>xxxxxx</username>
    </user>
    <cl>
        <id>21518</id>
        <id>21500</id>
    </cl>
</removeCL>
json
{
  "removeCL": {
    "user": {
      "username": "xxxxxx"
    },
    "cl": {
      "id": [
        "21518",
        "21500"
      ]
    }
  }
}
bash
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"
      ]
    }
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "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

StatusWhen
2cl or id is missing.
988Contact list are entered not exist.
511The account is not entitled to this operation.

addNumCL Add numbers to a list

Parameters

NameTypeDescriptionRequired
addNumCLobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️
clobjectThe list to update. Repeatable — several lists per call.✔️
cl.idintThe id of the contact list to update.✔️
destinationsobjectContains all the numbers to add to this list.✔️
destinationobjectOne contact. Repeatable.✔️
phoneintThe contact's number, formatted 5xxxxxxx or 05xxxxxxx.✔️
df1df6stringDynamic fields for this contact in this list.

Request example

xml
<?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>
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"
            }
          ]
        }
      }
    ]
  }
}
bash
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"
            }
          ]
        }
      }
    ]
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "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

StatusWhen
2cl, id or destinations is missing.
988The contact list does not exist.
511The 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

NameTypeDescriptionRequired
rmNumCLobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️
clobjectThe list to update. Repeatable.✔️
cl.idintThe id of the contact list to update.✔️
destinationsobjectContains the numbers to remove from this list.✔️
phoneintA number to remove, formatted 5xxxxxxx or 05xxxxxxx. Repeatable.✔️

Request example

xml
<?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>
json
{
  "rmNumCL": {
    "user": {
      "username": "xxxxxx"
    },
    "cl": [
      {
        "id": "21518",
        "destinations": {
          "phone": "055XXXXXXX"
        }
      },
      {
        "id": "21500",
        "destinations": {
          "phone": [
            "055XXXXXXX",
            "55XXXXXXX"
          ]
        }
      }
    ]
  }
}
bash
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"
          ]
        }
      }
    ]
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "status": 0,
  "message": "Successfully deleted phone numbers",
  "errors": [
    "contact list id: 21500 does not exist and therefore not removed"
  ]
}

Errors

StatusWhen
2cl, id or destinations is missing.
988The contact list does not exist.
511The 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

NameTypeDescriptionRequired
getCLobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️

Request example

xml
<?xml version="1.0" encoding="UTF-8"?>
<getCL>
    <user>
        <username>xxxxxx</username>
    </user>
</getCL>
json
{
  "getCL": {
    "user": {
      "username": "xxxxxx"
    }
  }
}
bash
curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
  "getCL": {
    "user": {
      "username": "xxxxxx"
    }
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "status": 0,
  "message": "",
  "contact_lists": [
    {
      "cl_id": "21518",
      "phone": "55XXXXXXX",
      "name": "name1"
    },
    {
      "cl_id": "21500",
      "phone": "555XXXXXX",
      "name": "name2"
    }
  ]
}
FieldTypeDescription
contact_listsarrayOne row per contact, not per list.
contact_lists[].cl_idstringThe list this contact belongs to.
contact_lists[].phonestringThe contact's number.
contact_lists[].namestringThe 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

StatusWhen
3, 10, 11Token invalid, expired, or belonging to another username.
511The account is not entitled to this operation.

getCLbyID Read one contact list

Parameters

NameTypeDescriptionRequired
getCLbyIDobjectContains all other elements.✔️
userobjectContains the user element.✔️
usernamestringThe username of the account by which you are recognized in the system.✔️
clobjectContains contact list elements.✔️
idintThe id of the contact list you want.✔️

Request example

xml
<?xml version="1.0" encoding="UTF-8"?>
<getCLbyID>
    <user>
        <username>xxxxxx</username>
    </user>
    <cl>
        <id>21518</id>
    </cl>
</getCLbyID>
json
{
  "getCLbyID": {
    "user": {
      "username": "xxxxxx"
    },
    "cl": {
      "id": "21518"
    }
  }
}
bash
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"
    }
  }
}'
js
// 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
<?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
<?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);
python
# 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)
go
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
// 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());
    }
}
csharp
// .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);
ruby
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
rust
// [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
<?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>
json
{
  "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

StatusWhen
2cl or id is missing.
988The contact list does not exist.
511The 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 df1df6 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.