מנויים
פעולות משווקים. חשבון שמשווק תעבורת TextMe יכול ליצור חשבונות משנה, לממן את הארנקים שלהם מהיתרה שלו, ולקרוא את היתרות שלהם.
POST https://my.textme.co.il/apiאם החשבון שלכם אינו משווק, הפעולות האלה מחזירות סטטוס 511 ואפשר לדלג על העמוד.
שני שמות משתמש, שני תפקידים
בכל העמוד הזה, user.username הוא החשבון שלכם — המשווק שמבצע את הפעולה — ו-userDetails.username הוא חשבון המשנה שעליו הפעולה מתבצעת. החלפה ביניהם היא הטעות הנפוצה ביותר כאן.
addSub יצירת חשבון משנה
יוצרת חשבון משנה עם פרטי התחברות, שולח ברירת מחדל ויתרת קרדיטים פותחת שנגרעת מהיתרה שלכם.
פרמטרים
| שם | סוג | תיאור | חובה |
|---|---|---|---|
addSub | object | מכיל את כל האלמנטים האחרים. | ✔️ |
user | object | מכיל את אלמנט המשתמש. | ✔️ |
user.username | string | שם המשתמש שלכם — חשבון המשווק. | ✔️ |
userDetails | object | פרטי המשתמש שברצונכם להוסיף. | ✔️ |
userDetails.name | string | שם התצוגה של המשתמש החדש. | ✔️ |
userDetails.username | string | שם המשתמש להתחברות של המשתמש החדש. | ✔️ |
userDetails.password | string | הסיסמה של המשתמש החדש. | ✔️ |
userDetails.source | string | שולח ברירת המחדל של המשתמש החדש. | ✔️ |
userDetails.amount | int | קרדיטים להעניק ביצירה, שנגרעים מהיתרה שלכם. | ✔️ |
userDetails.otpPhone | string | מספר טלפון לאימות OTP. | ➖ |
דוגמת בקשה
<?xml version="1.0" encoding="UTF-8"?>
<addSub>
<user>
<username>xxxxxx</username>
</user>
<userDetails>
<name>israel israeli</name>
<username>israelisraeli</username>
<password>israelisraeli</password>
<source>055xxxxxxx</source>
<amount>70000</amount>
<otpPhone>5xxxxxxxx</otpPhone>
</userDetails>
</addSub>{
"addSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx"
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"addSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx"
}
}
}'// Node.js 18+ / דפדפנים — ללא תלויות
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({
addSub: {
user: {
username: 'xxxxxx',
},
userDetails: {
name: 'israel israeli',
username: 'israelisraeli',
password: 'israelisraeli',
source: '055xxxxxxx',
amount: '70000',
otpPhone: '5xxxxxxxx',
},
},
}),
})
const result = await response.json()
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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' => [
'addSub' => [
'user' => [
'username' => 'xxxxxx',
],
'userDetails' => [
'name' => 'israel israeli',
'username' => 'israelisraeli',
'password' => 'israelisraeli',
'source' => '055xxxxxxx',
'amount' => '70000',
'otpPhone' => '5xxxxxxxx',
],
],
],
]);
$result = json_decode($response->getBody()->getContents(), true);
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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', [
'addSub' => [
'user' => [
'username' => 'xxxxxx',
],
'userDetails' => [
'name' => 'israel israeli',
'username' => 'israelisraeli',
'password' => 'israelisraeli',
'source' => '055xxxxxxx',
'amount' => '70000',
'otpPhone' => '5xxxxxxxx',
],
],
])
->throw()
->json();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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={
"addSub": {
"user": {
"username": "xxxxxx",
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx",
},
},
},
)
response.raise_for_status()
result = response.json()
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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{
"addSub": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"userDetails": map[string]any{
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx",
},
},
})
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)
}
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result.Status.String() != "0" {
panic(fmt.Sprintf("TextMe %s: %s", result.Status, result.Message))
}
fmt.Println(result.Message)
}// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TextMeSubscriberAdd {
public static void main(String[] args) throws Exception {
String body = """
{
"addSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx"
}
}
}
""";
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());
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"addSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx"
}
}
}
""";
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();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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({
"addSub" => {
"user" => {
"username" => "xxxxxx",
},
"userDetails" => {
"name" => "israel israeli",
"username" => "israelisraeli",
"password" => "israelisraeli",
"source" => "055xxxxxxx",
"amount" => "70000",
"otpPhone" => "5xxxxxxxx",
},
},
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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!({
"addSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"name": "israel israeli",
"username": "israelisraeli",
"password": "israelisraeli",
"source": "055xxxxxxx",
"amount": "70000",
"otpPhone": "5xxxxxxxx"
}
}
}))
.send()
.await?
.json()
.await?;
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result["status"] != 0 {
return Err(format!("TextMe {}: {}", result["status"], result["message"]).into());
}
println!("{result}");
Ok(())
}תשובה
<?xml version="1.0" encoding="UTF-8"?>
<addSub>
<status>0</status>
<message>The user was created successfully</message>
</addSub>{
"status": 0,
"message": "The user was created successfully"
}userDetails.amount הוא הקרדיט הפותח, שנגרע מהיתרה שלכם. otpPhone הוא אופציונלי ומאפשר אימות OTP למשתמש החדש.
| Status | משמעות |
|---|---|
990 | הסכום עובר את הקרדיט שיש לכם. |
991 | הסכום מכיל משהו שאינו ספרות. |
992 | ה-source ארוך או קצר מדי. |
993 | אורך הסיסמה נדחה. |
994 | שם המשתמש הזה כבר קיים — בחרו אחר. |
995 | אורך שם המשתמש נדחה. |
996 | אורך שם התצוגה נדחה. |
511 | החשבון שלכם אינו רשאי ליצור חשבונות משנה. |
הסיסמה עוברת בגוף הבקשה כטקסט גלוי
TLS מגן עליה בתעבורה, אבל היא תגיע לכל לוג בקשות שאתם שומרים. הסתירו את userDetails.password לפני תיעוד, וגנרטו את הערך במקום לתת לאדם לבחור אותו:
const password = crypto.randomBytes(18).toString('base64url')בדקו כפילות לפני היצירה
אין פעולה שבודקת "האם שם המשתמש הזה קיים", וכשל ביצירה לא מספר לכם דבר נוסף. נהלו רישום משלכם של שמות המשתמש שהנפקתם, כך שהתנגשות תיתפס לפני הקריאה ולא אחריה.
updateAmountSub טעינת ארנק
מעבירה קרדיטים לארנק של חשבון משנה.
פרמטרים
| שם | סוג | תיאור | חובה |
|---|---|---|---|
updateAmountSub | object | מכיל את כל האלמנטים האחרים. | ✔️ |
user | object | מכיל את אלמנט המשתמש. | ✔️ |
user.username | string | שם המשתמש שלכם — חשבון המשווק. | ✔️ |
userDetails | object | פרטי המשתמש שברצונכם לעדכן. | ✔️ |
userDetails.username | string | שם המשתמש הפנימי של חשבון המשנה. | ✔️ |
userDetails.amount | int | קרדיטים להעניק. | ✔️ |
userDetails.amount_int | int | שלחו אותו במקום amount כדי לעדכן את יתרת הכסף של חשבון המשנה ולא את קרדיטי ההודעות. שלחו אותו בלי אלמנט amount. | ➖ |
amount ו-amount_int הם חלופות
amount מעביר קרדיטים של הודעות; amount_int מעביר כסף. שלחו אחד מהם, מעולם לא את שניהם — amount_int מתועד כמחליף את amount, לא כמשלים אותו.
דוגמת בקשה
<?xml version="1.0" encoding="UTF-8"?>
<updateAmountSub>
<user>
<username>xxxxxx</username>
</user>
<userDetails>
<username>username1</username>
<amount>70000</amount>
</userDetails>
</updateAmountSub>{
"updateAmountSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"username": "username1",
"amount": "70000"
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"updateAmountSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"username": "username1",
"amount": "70000"
}
}
}'// Node.js 18+ / דפדפנים — ללא תלויות
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({
updateAmountSub: {
user: {
username: 'xxxxxx',
},
userDetails: {
username: 'username1',
amount: '70000',
},
},
}),
})
const result = await response.json()
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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' => [
'updateAmountSub' => [
'user' => [
'username' => 'xxxxxx',
],
'userDetails' => [
'username' => 'username1',
'amount' => '70000',
],
],
],
]);
$result = json_decode($response->getBody()->getContents(), true);
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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', [
'updateAmountSub' => [
'user' => [
'username' => 'xxxxxx',
],
'userDetails' => [
'username' => 'username1',
'amount' => '70000',
],
],
])
->throw()
->json();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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={
"updateAmountSub": {
"user": {
"username": "xxxxxx",
},
"userDetails": {
"username": "username1",
"amount": "70000",
},
},
},
)
response.raise_for_status()
result = response.json()
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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{
"updateAmountSub": map[string]any{
"user": map[string]any{
"username": "xxxxxx",
},
"userDetails": map[string]any{
"username": "username1",
"amount": "70000",
},
},
})
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)
}
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result.Status.String() != "0" {
panic(fmt.Sprintf("TextMe %s: %s", result.Status, result.Message))
}
fmt.Println(result.Message)
}// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TextMeSubscriberWallet {
public static void main(String[] args) throws Exception {
String body = """
{
"updateAmountSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"username": "username1",
"amount": "70000"
}
}
}
""";
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());
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"updateAmountSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"username": "username1",
"amount": "70000"
}
}
}
""";
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();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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({
"updateAmountSub" => {
"user" => {
"username" => "xxxxxx",
},
"userDetails" => {
"username" => "username1",
"amount" => "70000",
},
},
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
result = JSON.parse(response.body)
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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!({
"updateAmountSub": {
"user": {
"username": "xxxxxx"
},
"userDetails": {
"username": "username1",
"amount": "70000"
}
}
}))
.send()
.await?
.json()
.await?;
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result["status"] != 0 {
return Err(format!("TextMe {}: {}", result["status"], result["message"]).into());
}
println!("{result}");
Ok(())
}תשובה
<?xml version="1.0" encoding="UTF-8"?>
<updateAmountSub>
<status>0</status>
<message>Wallet successfully updated</message>
</updateAmountSub>{
"status": 0,
"message": "Wallet successfully updated"
}שגיאות
| Status | מתי |
|---|---|
990 | הסכום עובר את הקרדיט שיש לכם. |
991 | הסכום מכיל משהו שאינו ספרות. |
503 | ה-userDetails.username אינו אחד מחשבונות המשנה שלכם. |
511 | החשבון שלכם אינו רשאי לבצע את הפעולה. |
לא אידמפוטנטי
אין מזהה בקשה ואין סילוק כפילויות. שתי קריאות מעניקות את הקרדיט פעמיים, ואין פעולת API שמחזירה אותו.
אם טעינה נכשלת בטיים-אאוט, אל תנסו אותה שוב. קראו את היתרה עם getBlanceSubs והחליטו לפי המספר בפועל:
// טיים-אאוט לא מספר לכם דבר. קראו את המצב, ואז החליטו.
const before = await subAccountBalance('username1')
try {
await textme(topUp('username1', 5000))
} catch (timeout) {
const after = await subAccountBalance('username1')
// נסו שוב רק אם ניתן להראות שהקרדיט לא נכנס.
if (after === before) await textme(topUp('username1', 5000))
}getBlanceSubs קריאת כל היתרות
מחזירה את היתרה של כל חשבון משנה בקריאה אחת. שימו לב לשגיאת הכתיב — אלמנט השורש הוא באמת getBlanceSubs:
פרמטרים
| שם | סוג | תיאור | חובה |
|---|---|---|---|
getBlanceSubs | object | מכיל את כל האלמנטים האחרים. | ✔️ |
user | object | מכיל את אלמנט המשתמש. | ✔️ |
username | string | שם המשתמש שלכם — חשבון המשווק. | ✔️ |
getBlanceSubs, לא getBalanceSubs
איות נכון מחזיר סטטוס 997, Not a valid command sent. שימו הערה בקוד לידו כדי שאף אחד לא "יתקן" את שגיאת הכתיב.
דוגמת בקשה
<?xml version="1.0" encoding="UTF-8"?>
<getBlanceSubs>
<user>
<username>xxxxxx</username>
</user>
</getBlanceSubs>{
"getBlanceSubs": {
"user": {
"username": "xxxxxx"
}
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"getBlanceSubs": {
"user": {
"username": "xxxxxx"
}
}
}'// Node.js 18+ / דפדפנים — ללא תלויות
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({
getBlanceSubs: {
user: {
username: 'xxxxxx',
},
},
}),
})
const result = await response.json()
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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' => [
'getBlanceSubs' => [
'user' => [
'username' => 'xxxxxx',
],
],
],
]);
$result = json_decode($response->getBody()->getContents(), true);
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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', [
'getBlanceSubs' => [
'user' => [
'username' => 'xxxxxx',
],
],
])
->throw()
->json();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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={
"getBlanceSubs": {
"user": {
"username": "xxxxxx",
},
},
},
)
response.raise_for_status()
result = response.json()
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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{
"getBlanceSubs": 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)
}
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result.Status.String() != "0" {
panic(fmt.Sprintf("TextMe %s: %s", result.Status, result.Message))
}
fmt.Println(result.Message)
}// Java 17+ — java.net.http, ללא תלויות (פענוח עם Jackson/Gson)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class TextMeSubscriberBalances {
public static void main(String[] args) throws Exception {
String body = """
{
"getBlanceSubs": {
"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());
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
System.out.println(response.body());
}
}// .NET 8+ — System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"getBlanceSubs": {
"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();
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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({
"getBlanceSubs" => {
"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)
# גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
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!({
"getBlanceSubs": {
"user": {
"username": "xxxxxx"
}
}
}))
.send()
.await?
.json()
.await?;
// גם שגיאה חוזרת כ-HTTP 200 — הסטטוס שבגוף התשובה הוא הקובע
if result["status"] != 0 {
return Err(format!("TextMe {}: {}", result["status"], result["message"]).into());
}
println!("{result}");
Ok(())
}תשובה
<?xml version="1.0" encoding="UTF-8"?>
<getBlanceSubs>
<status>0</status>
<message></message>
<balances>
<balance>
<amount>80</amount>
<sms_user_id>xxx</sms_user_id>
<name>name1</name>
</balance>
<balance>
<amount>50</amount>
<sms_user_id>xxx</sms_user_id>
<name>name2</name>
</balance>
</balances>
</getBlanceSubs>{
"status": 0,
"message": "",
"balances": [
{
"amount": "80",
"sms_user_id": "XXXX",
"name": "name1"
},
{
"amount": "50",
"sms_user_id": "XXXX",
"name": "name2"
}
]
}| שדה | סוג | תיאור |
|---|---|---|
balances | array | רשומה אחת לכל חשבון משנה. |
balances[].amount | string | הקרדיטים שנותרו. |
balances[].sms_user_id | string | המזהה הפנימי של חשבון המשנה. |
balances[].name | string | שם התצוגה שלו. |
בתשובה אין username
הרשומות נושאות name ו-sms_user_id, אבל לא את שם המשתמש להתחברות שהעברתם ל-addSub. כדי למפות יתרות לרשומות שלכם, שמרו את sms_user_id — או שמרו על name ייחודי ומשמעותי.
שגיאות
| Status | מתי |
|---|---|
3, 10, 11 | טוקן לא תקף, פג תוקף, או שייך ל-username אחר. |
511 | החשבון שלכם אינו רשאי לבצע את הפעולה. |
הערות על השדות
קרדיט זורם בכיוון אחד דרך ה-API
addSub ו-updateAmountSub מעבירות קרדיט מכם לחשבון משנה. אין פעולה שמחזירה אותו. העניקו בסכומים שאתם באמת מתכוונים להעביר, וטענו בתכיפות גבוהה יותר במקום בבלוקים גדולים.
פעולה בשם חשבון משנה
הטוקן שלכם מאמת; user.username בוחר עבור מי הפעולה מתבצעת. הגדירו אותו לשם משתמש של חשבון משנה ותוכלו לשלוח, לקרוא דוחות ולנהל רשימות בשמו — ראו אימות. החשבון חייב להיות אחד משלכם, אחרת הקריאה נכשלת ב-503.
חשבונות משנה מאמתים את השולחים שלהם; getVerifiedPhones עם is_subs: 1 נותן לכם מבט על כולם.

