Skip to content

מנויים

פעולות משווקים. חשבון שמשווק תעבורת TextMe יכול ליצור חשבונות משנה, לממן את הארנקים שלהם מהיתרה שלו, ולקרוא את היתרות שלהם.

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

אם החשבון שלכם אינו משווק, הפעולות האלה מחזירות סטטוס 511 ואפשר לדלג על העמוד.

שני שמות משתמש, שני תפקידים

בכל העמוד הזה, user.username הוא החשבון שלכם — המשווק שמבצע את הפעולה — ו-userDetails.username הוא חשבון המשנה שעליו הפעולה מתבצעת. החלפה ביניהם היא הטעות הנפוצה ביותר כאן.

addSub יצירת חשבון משנה

יוצרת חשבון משנה עם פרטי התחברות, שולח ברירת מחדל ויתרת קרדיטים פותחת שנגרעת מהיתרה שלכם.

פרמטרים

שםסוגתיאורחובה
addSubobjectמכיל את כל האלמנטים האחרים.✔️
userobjectמכיל את אלמנט המשתמש.✔️
user.usernamestringשם המשתמש שלכם — חשבון המשווק.✔️
userDetailsobjectפרטי המשתמש שברצונכם להוסיף.✔️
userDetails.namestringשם התצוגה של המשתמש החדש.✔️
userDetails.usernamestringשם המשתמש להתחברות של המשתמש החדש.✔️
userDetails.passwordstringהסיסמה של המשתמש החדש.✔️
userDetails.sourcestringשולח ברירת המחדל של המשתמש החדש.✔️
userDetails.amountintקרדיטים להעניק ביצירה, שנגרעים מהיתרה שלכם.✔️
userDetails.otpPhonestringמספר טלפון לאימות OTP.

דוגמת בקשה

xml
<?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>
json
{
  "addSub": {
    "user": {
      "username": "xxxxxx"
    },
    "userDetails": {
      "name": "israel israeli",
      "username": "israelisraeli",
      "password": "israelisraeli",
      "source": "055xxxxxxx",
      "amount": "70000",
      "otpPhone": "5xxxxxxxx"
    }
  }
}
bash
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"
    }
  }
}'
js
// 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
<?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
<?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);
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={
        "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)
go
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
// 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());
    }
}
csharp
// .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);
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({
  "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
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!({
          "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
<?xml version="1.0" encoding="UTF-8"?>
<addSub>
    <status>0</status>
    <message>The user was created successfully</message>
</addSub>
json
{
  "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 לפני תיעוד, וגנרטו את הערך במקום לתת לאדם לבחור אותו:

js
const password = crypto.randomBytes(18).toString('base64url')

בדקו כפילות לפני היצירה

אין פעולה שבודקת "האם שם המשתמש הזה קיים", וכשל ביצירה לא מספר לכם דבר נוסף. נהלו רישום משלכם של שמות המשתמש שהנפקתם, כך שהתנגשות תיתפס לפני הקריאה ולא אחריה.

updateAmountSub טעינת ארנק

מעבירה קרדיטים לארנק של חשבון משנה.

פרמטרים

שםסוגתיאורחובה
updateAmountSubobjectמכיל את כל האלמנטים האחרים.✔️
userobjectמכיל את אלמנט המשתמש.✔️
user.usernamestringשם המשתמש שלכם — חשבון המשווק.✔️
userDetailsobjectפרטי המשתמש שברצונכם לעדכן.✔️
userDetails.usernamestringשם המשתמש הפנימי של חשבון המשנה.✔️
userDetails.amountintקרדיטים להעניק.✔️
userDetails.amount_intintשלחו אותו במקום amount כדי לעדכן את יתרת הכסף של חשבון המשנה ולא את קרדיטי ההודעות. שלחו אותו בלי אלמנט amount.

amount ו-amount_int הם חלופות

amount מעביר קרדיטים של הודעות; amount_int מעביר כסף. שלחו אחד מהם, מעולם לא את שניהם — amount_int מתועד כמחליף את amount, לא כמשלים אותו.

דוגמת בקשה

xml
<?xml version="1.0" encoding="UTF-8"?>
<updateAmountSub>
    <user>
        <username>xxxxxx</username>
    </user>
    <userDetails>
        <username>username1</username>
        <amount>70000</amount>
    </userDetails>
</updateAmountSub>
json
{
  "updateAmountSub": {
    "user": {
      "username": "xxxxxx"
    },
    "userDetails": {
      "username": "username1",
      "amount": "70000"
    }
  }
}
bash
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"
    }
  }
}'
js
// 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
<?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
<?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);
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={
        "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)
go
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
// 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());
    }
}
csharp
// .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);
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({
  "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
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!({
          "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
<?xml version="1.0" encoding="UTF-8"?>
<updateAmountSub>
    <status>0</status>
    <message>Wallet successfully updated</message>
</updateAmountSub>
json
{
  "status": 0,
  "message": "Wallet successfully updated"
}

שגיאות

Statusמתי
990הסכום עובר את הקרדיט שיש לכם.
991הסכום מכיל משהו שאינו ספרות.
503ה-userDetails.username אינו אחד מחשבונות המשנה שלכם.
511החשבון שלכם אינו רשאי לבצע את הפעולה.

לא אידמפוטנטי

אין מזהה בקשה ואין סילוק כפילויות. שתי קריאות מעניקות את הקרדיט פעמיים, ואין פעולת API שמחזירה אותו.

אם טעינה נכשלת בטיים-אאוט, אל תנסו אותה שוב. קראו את היתרה עם getBlanceSubs והחליטו לפי המספר בפועל:

js
// טיים-אאוט לא מספר לכם דבר. קראו את המצב, ואז החליטו.
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:

פרמטרים

שםסוגתיאורחובה
getBlanceSubsobjectמכיל את כל האלמנטים האחרים.✔️
userobjectמכיל את אלמנט המשתמש.✔️
usernamestringשם המשתמש שלכם — חשבון המשווק.✔️

getBlanceSubs, לא getBalanceSubs

איות נכון מחזיר סטטוס 997, Not a valid command sent. שימו הערה בקוד לידו כדי שאף אחד לא "יתקן" את שגיאת הכתיב.

דוגמת בקשה

xml
<?xml version="1.0" encoding="UTF-8"?>
<getBlanceSubs>
    <user>
        <username>xxxxxx</username>
    </user>
</getBlanceSubs>
json
{
  "getBlanceSubs": {
    "user": {
      "username": "xxxxxx"
    }
  }
}
bash
curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
  "getBlanceSubs": {
    "user": {
      "username": "xxxxxx"
    }
  }
}'
js
// 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
<?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
<?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);
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={
        "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)
go
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
// 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());
    }
}
csharp
// .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);
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({
  "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
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!({
          "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
<?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>
json
{
  "status": 0,
  "message": "",
  "balances": [
    {
      "amount": "80",
      "sms_user_id": "XXXX",
      "name": "name1"
    },
    {
      "amount": "50",
      "sms_user_id": "XXXX",
      "name": "name2"
    }
  ]
}
שדהסוגתיאור
balancesarrayרשומה אחת לכל חשבון משנה.
balances[].amountstringהקרדיטים שנותרו.
balances[].sms_user_idstringהמזהה הפנימי של חשבון המשנה.
balances[].namestringשם התצוגה שלו.

בתשובה אין 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 נותן לכם מבט על כולם.