Reports
Three read operations: delivery reports by your own external id, delivery reports by date window, and messages people sent to you.
POST https://my.textme.co.il/apiAll three are polling operations. To have the same data pushed to you as it arrives instead, register a push URL.
dlr Delivery reports by external id
Returns what happened to specific messages — the ones you tagged with an id attribute on <phone> when sending.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
dlr | 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. | ✔️ |
transactions | object | Contains the ids you want reports for. May hold multiple external_id elements. | ✔️ |
external_id | string | The id you sent as an attribute when submitting the SMS. | ✔️ |
from | string | Start of the window, formatted dd/mm/yy hh:mm. | ✔️ |
to | string | End of the window, formatted dd/mm/yy hh:mm. | ✔️ |
Two limits apply
- The window between
fromandtomay not exceed one week. - At most 1,000
external_idvalues per request.
Request example
<?xml version="1.0" encoding="UTF-8"?>
<dlr>
<user>
<username>Leeroy</username>
</user>
<transactions>
<external_id>some id 1</external_id>
<external_id>some id 2</external_id>
</transactions>
<from>01/01/14 00:00</from>
<to>01/01/14 23:59</to>
</dlr>{
"dlr": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": [
"some id 1",
"some id 2"
]
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"dlr": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": [
"some id 1",
"some id 2"
]
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59"
}
}'// 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({
dlr: {
user: {
username: 'Leeroy',
},
transactions: {
external_id: [
'some id 1',
'some id 2',
],
},
from: '01/01/14 00:00',
to: '01/01/14 23:59',
},
}),
})
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' => [
'dlr' => [
'user' => [
'username' => 'Leeroy',
],
'transactions' => [
'external_id' => [
'some id 1',
'some id 2',
],
],
'from' => '01/01/14 00:00',
'to' => '01/01/14 23:59',
],
],
]);
$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', [
'dlr' => [
'user' => [
'username' => 'Leeroy',
],
'transactions' => [
'external_id' => [
'some id 1',
'some id 2',
],
],
'from' => '01/01/14 00:00',
'to' => '01/01/14 23:59',
],
])
->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={
"dlr": {
"user": {
"username": "Leeroy",
},
"transactions": {
"external_id": [
"some id 1",
"some id 2",
],
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59",
},
},
)
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{
"dlr": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"transactions": map[string]any{
"external_id": []any{
"some id 1",
"some id 2",
},
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59",
},
})
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 TextMeDlr {
public static void main(String[] args) throws Exception {
String body = """
{
"dlr": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": [
"some id 1",
"some id 2"
]
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59"
}
}
""";
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 = """
{
"dlr": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": [
"some id 1",
"some id 2"
]
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59"
}
}
""";
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({
"dlr" => {
"user" => {
"username" => "Leeroy",
},
"transactions" => {
"external_id" => [
"some id 1",
"some id 2",
],
},
"from" => "01/01/14 00:00",
"to" => "01/01/14 23:59",
},
})
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!({
"dlr": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": [
"some id 1",
"some id 2"
]
},
"from": "01/01/14 00:00",
"to": "01/01/14 23:59"
}
}))
.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"?>
<dlr>
<status>0</status>
<message></message>
<transactions>
<transaction>
<external_id>1391438285</external_id>
<status>102</status>
<he_message>הגיע ליעד</he_message>
<en_message>Delivered</en_message>
<date>03/02/14 16:38</date>
<shipment_id>12345678</shipment_id>
</transaction>
</transactions>
</dlr>{
"status": 0,
"message": "all is well!",
"transactions": [
{
"external_id": "1391438285",
"source": "Test",
"phone": "5XXXXXXXX",
"status": "102",
"message_he": "הגיע ליעד",
"en_message": "Delivered",
"shipment_id": "XXXXXXX",
"date": "02/05/23 10:22",
"operator": "Telzar"
}
]
}| Field | Type | Description |
|---|---|---|
status | int | 0 — the report was produced. Says nothing about delivery. |
message | string | Note about the request itself. |
transactions | array | One entry per message, described below. |
transactions[]
| Field | Type | Description |
|---|---|---|
external_id | string | The id you supplied when sending. |
source | string | The sender the message went out as. |
phone | string | The destination. |
status | string | The delivery status — the DLR status vocabulary, not the request status codes. |
he_message / message_he | string | The status in Hebrew. See the naming note below. |
en_message | string | The status in English, e.g. Delivered. |
date | string | When the status was recorded, dd/mm/yy hh:mm. |
shipment_id | string | The campaign the message belonged to. |
operator | string | The carrier that handled it, e.g. Telzar. |
The Hebrew field is named differently in each encoding
XML returns <he_message>; JSON returns message_he. The English one is en_message in both. Read whichever your parser is actually looking at — a client written against the XML shape will silently find nothing in the JSON one.
Errors
| Status | When |
|---|---|
2 | from, to or transactions is missing. |
3, 10, 11 | Token invalid, expired, or belonging to another username. |
511 | The account is not entitled to this operation. |
dlrByDate Delivery reports by date
The same report without needing ids — everything the account sent inside a time window. Use it when you did not set external ids, or when reconciling in bulk rather than looking up a specific message.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
dlrByDate | 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. | ✔️ |
transactions | object | Present but not used for filtering. | ✔️ |
external_id | string | Send the literal string null. | ✔️ |
from | string | Start of the window, dd/mm/yy hh:mm. | ✔️ |
to | string | End of the window, dd/mm/yy hh:mm. | ✔️ |
One limit applies
The window between from and to may not exceed one week.
Request example
<?xml version="1.0" encoding="UTF-8"?>
<dlrByDate>
<user>
<username>Leeroy</username>
</user>
<transactions>
<external_id>null</external_id>
</transactions>
<from>04/09/22 00:00</from>
<to>04/09/22 23:59</to>
</dlrByDate>{
"dlrByDate": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": "null"
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"dlrByDate": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": "null"
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59"
}
}'// 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({
dlrByDate: {
user: {
username: 'Leeroy',
},
transactions: {
external_id: 'null',
},
from: '04/09/22 00:00',
to: '04/09/22 23:59',
},
}),
})
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' => [
'dlrByDate' => [
'user' => [
'username' => 'Leeroy',
],
'transactions' => [
'external_id' => 'null',
],
'from' => '04/09/22 00:00',
'to' => '04/09/22 23:59',
],
],
]);
$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', [
'dlrByDate' => [
'user' => [
'username' => 'Leeroy',
],
'transactions' => [
'external_id' => 'null',
],
'from' => '04/09/22 00:00',
'to' => '04/09/22 23:59',
],
])
->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={
"dlrByDate": {
"user": {
"username": "Leeroy",
},
"transactions": {
"external_id": "null",
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59",
},
},
)
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{
"dlrByDate": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"transactions": map[string]any{
"external_id": "null",
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59",
},
})
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 TextMeDlrByDate {
public static void main(String[] args) throws Exception {
String body = """
{
"dlrByDate": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": "null"
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59"
}
}
""";
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 = """
{
"dlrByDate": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": "null"
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59"
}
}
""";
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({
"dlrByDate" => {
"user" => {
"username" => "Leeroy",
},
"transactions" => {
"external_id" => "null",
},
"from" => "04/09/22 00:00",
"to" => "04/09/22 23:59",
},
})
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!({
"dlrByDate": {
"user": {
"username": "Leeroy"
},
"transactions": {
"external_id": "null"
},
"from": "04/09/22 00:00",
"to": "04/09/22 23:59"
}
}))
.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"?>
<dlr>
<status>0</status>
<message></message>
<transactions>
<transaction>
<external_id>1391438285</external_id>
<status>102</status>
<he_message>הגיע ליעד</he_message>
<en_message>Delivered</en_message>
<date>03/02/14 16:38</date>
<shipment_id>12345678</shipment_id>
</transaction>
</transactions>
</dlr>{
"status": 0,
"message": "all is well!",
"transactions": [
{
"external_id": "1391438285",
"source": "Test",
"phone": "5XXXXXXXX",
"status": "102",
"message_he": "הגיע ליעד",
"en_message": "Delivered",
"shipment_id": "XXXXXXX",
"date": "02/05/23 10:22",
"operator": "Telzar"
}
]
}Identical in shape to dlr — including the root element, which comes back as <dlr> rather than <dlrByDate>. Transactions carry the same fields.
Errors
Same as dlr, plus 2 when the window exceeds a week.
incoming Incoming messages
Messages sent to your numbers — replies to a campaign, opt-out keywords, or anything else a recipient texts back.
Parameters
| Name | Type | Description | Required |
|---|---|---|---|
incoming | 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. | ✔️ |
from | string | Start of the window, dd/mm/yy hh:mm. | ✔️ |
to | string | End of the window, dd/mm/yy hh:mm. | ✔️ |
Window limits
A range of one week per request, reaching up to one year back.
Request example
<?xml version="1.0" encoding="UTF-8"?>
<incoming>
<user>
<username>Leeroy</username>
</user>
<from>01/11/22 00:00</from>
<to>01/11/22 23:59</to>
</incoming>{
"incoming": {
"user": {
"username": "Leeroy"
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"incoming": {
"user": {
"username": "Leeroy"
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59"
}
}'// 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({
incoming: {
user: {
username: 'Leeroy',
},
from: '01/11/22 00:00',
to: '01/11/22 23:59',
},
}),
})
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' => [
'incoming' => [
'user' => [
'username' => 'Leeroy',
],
'from' => '01/11/22 00:00',
'to' => '01/11/22 23:59',
],
],
]);
$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', [
'incoming' => [
'user' => [
'username' => 'Leeroy',
],
'from' => '01/11/22 00:00',
'to' => '01/11/22 23:59',
],
])
->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={
"incoming": {
"user": {
"username": "Leeroy",
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59",
},
},
)
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{
"incoming": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59",
},
})
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 TextMeIncoming {
public static void main(String[] args) throws Exception {
String body = """
{
"incoming": {
"user": {
"username": "Leeroy"
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59"
}
}
""";
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 = """
{
"incoming": {
"user": {
"username": "Leeroy"
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59"
}
}
""";
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({
"incoming" => {
"user" => {
"username" => "Leeroy",
},
"from" => "01/11/22 00:00",
"to" => "01/11/22 23:59",
},
})
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!({
"incoming": {
"user": {
"username": "Leeroy"
},
"from": "01/11/22 00:00",
"to": "01/11/22 23:59"
}
}))
.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"?>
<incoming>
<status>0</status>
<message></message>
<transactions>
<transaction>
<source>05********</source>
<destination>05********</destination>
<message>This is a sample message</message>
<date>03/12/14 16:38</date>
</transaction>
</transactions>
</incoming>{
"status": 0,
"message": "",
"transactions": [
{
"source": "test",
"destination": "9725XXXXXXX",
"message": "test",
"date": "01/05/23 00:00"
}
]
}transactions[]
| Field | Type | Description |
|---|---|---|
source | string | The number that sent the message. |
destination | string | The number of yours it arrived on. |
message | string | The text received. |
date | string | When it arrived, dd/mm/yy hh:mm. |
Errors
Same as dlr.
Field notes
Choosing between dlr and dlrByDate
dlr | dlrByDate | |
|---|---|---|
| Needs external ids | yes | no |
| Answers "what happened to this message" | yes | only by scanning |
| Answers "how did yesterday go" | awkward | yes |
| Per-request ceiling | 1,000 ids | whatever the window holds |
For transactional traffic, set an id on every destination and use dlr. For campaign reporting, dlrByDate over the window the campaign ran is simpler.
Reports are not immediate
A delivery status is produced when the carrier reports back, which can be seconds or minutes after the send — and for an unreachable handset, considerably longer. Polling one second after sending will mostly return nothing, or an unconfirmed status.
Poll on a schedule over a window that trails the present, or use the push API and stop polling.
Paging
There is no page cursor. The window is the pagination: to walk a month of history under the one-week ceiling, issue four or five sequential requests, each covering its own slice. Keep the slices from overlapping and you will not have to deduplicate.

