OTP
שולחת קוד חד-פעמי ב-SMS ומאמתת אותו בחזרה. TextMe מייצרת את הקוד, שומרת אותו מול מספר הטלפון, סופרת את הניסיונות ומפקיעה אותו, כך שאינכם צריכים לייצר או לשמור קודים בעצמכם.
POST https://my.textme.co.il/apiשתי פעולות: send_otp מנפיקה קוד, ו-validate_otp מאמתת אותו.
מאיפה זה מגיע
שתי הפעולות האלה מתועדות על ידי TextMe בכתובת docs.textme.co.il/otp/, שהיא בילד תיעוד שני על אותו שרת שטבלת הנתיבים של האתר הראשי אינה מכילה. הפרמטרים, גופי הבקשה ונוסח התשובות למטה הם של הספק.
הן גם הסיבה לכך שטבלת קודי הסטטוס שלנו כוללת את 12 במשמעות "When verifying OTP code: Unverified code".
send_otp שליחת קוד חד-פעמי
מייצרת קוד, שולחת אותו ב-SMS, ומתחילה את חלון התוקף.
פרמטרים
| שם | סוג | תיאור | חובה |
|---|---|---|---|
send_otp | object | אלמנט השורש. | ✔️ |
user | object | מכיל את אלמנט המשתמש. | ✔️ |
username | string | שם המשתמש של החשבון שבו אתם מזוהים במערכת. | ✔️ |
phone | int | היעד, בפורמט 5xxxxxxx או 05xxxxxxx. | ✔️ |
source | string | השולח שממנו הקוד ייראה כאילו נשלח. חייב להיות שולח מאומת. | ✔️ |
app_id | int | מפריד בין אפליקציות כשחשבון אחד משרת כמה מהן. ברירת המחדל היא 1. | ➖ |
max_tries | int | כמה ניסיונות אימות הקוד מאפשר, בין 3 ל-5. ברירת המחדל היא 3. | ➖ |
valid_time | int | כמה דקות הקוד נשאר בתוקף, בין 1 ל-15. ברירת המחדל היא 5. | ➖ |
text | string | נוסח ההודעה שלכם. חייב להכיל [code], שיוחלף בקוד שנוצר. ברירת המחדל היא the code is [code]. | ➖ |
דוגמת בקשה
<?xml version="1.0" encoding="UTF-8"?>
<send_otp>
<user>
<username>Leeroy</username>
</user>
<phone>5xxxxxxxx</phone>
<source>DemoAPI</source>
<app_id>1</app_id>
<max_tries>3</max_tries>
<valid_time>5</valid_time>
<text>Your DemoAPI code is [code]</text>
</send_otp>{
"send_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"send_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]"
}
}'// 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({
send_otp: {
user: {
username: 'Leeroy',
},
phone: '5xxxxxxxx',
source: 'DemoAPI',
app_id: '1',
max_tries: '3',
valid_time: '5',
text: 'Your DemoAPI code is [code]',
},
}),
})
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' => [
'send_otp' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => '5xxxxxxxx',
'source' => 'DemoAPI',
'app_id' => '1',
'max_tries' => '3',
'valid_time' => '5',
'text' => 'Your DemoAPI code is [code]',
],
],
]);
$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', [
'send_otp' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => '5xxxxxxxx',
'source' => 'DemoAPI',
'app_id' => '1',
'max_tries' => '3',
'valid_time' => '5',
'text' => 'Your DemoAPI code is [code]',
],
])
->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={
"send_otp": {
"user": {
"username": "Leeroy",
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]",
},
},
)
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{
"send_otp": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]",
},
})
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 TextMeOtpSend {
public static void main(String[] args) throws Exception {
String body = """
{
"send_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]"
}
}
""";
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+ using System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"send_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]"
}
}
""";
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({
"send_otp" => {
"user" => {
"username" => "Leeroy",
},
"phone" => "5xxxxxxxx",
"source" => "DemoAPI",
"app_id" => "1",
"max_tries" => "3",
"valid_time" => "5",
"text" => "Your DemoAPI code is [code]",
},
})
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!({
"send_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"source": "DemoAPI",
"app_id": "1",
"max_tries": "3",
"valid_time": "5",
"text": "Your DemoAPI code is [code]"
}
}))
.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"?>
<sms>
<status>0</status>
<code>448431</code>
<message>The code is : 448431 and is valid for 5 minutes</message>
</sms>{
"status": 0,
"code": "448431",
"message": "The code is : 448431 and is valid for 5 minutes"
}status בערך 0 אומר שהקוד נוצר וה-SMS נתקבל לשליחה.
שימו לב למבנה התשובה: אלמנט השורש הוא sms ולא send_otp, והקוד שנוצר חוזר בשדה code, עם אותו ערך שחוזר גם בתוך message.
התשובה מכילה את הקוד
send_otp מחזירה לקורא את הקוד בטקסט גלוי. כל דבר שמתעד את גוף התשובה, כלי APM, מדווח שגיאות, לוג דיבאג, מתעד קוד חד-פעמי פעיל עבור אותו מספר טלפון.
הסתירו את code ואת message לפני תיעוד. אינכם צריכים אף אחד מהערכים כדי להשלים את התהליך: המכשיר מקבל את הקוד, ו-validate_otp אומרת לכם אם המשתמש הקליד אותו נכון.
שגיאות
| Status | מתי |
|---|---|
2 | חסר אלמנט חובה; ה-message מציין איזה. |
4 | אין מספיק יתרה לשליחת ה-SMS. |
9 | ה-phone קצר או ארוך מדי. |
515 | ה-source אינו שולח מאומת. |
989 | ה-text ריק או עובר את מגבלת אורך ההודעה. |
validate_otp אימות קוד חד-פעמי
מאמתת קוד שהמשתמש הקליד מול הקוד השמור עבור אותו טלפון ואותו app_id.
פרמטרים
| שם | סוג | תיאור | חובה |
|---|---|---|---|
validate_otp | object | אלמנט השורש. | ✔️ |
user | object | מכיל את אלמנט המשתמש. | ✔️ |
username | string | שם המשתמש של החשבון שבו אתם מזוהים במערכת. | ✔️ |
phone | int | המספר שאליו נשלח הקוד, בפורמט 5xxxxxxx או 05xxxxxxx. | ✔️ |
code | int | הקוד בן שש הספרות לאימות. | ✔️ |
app_id | int | חייב להתאים ל-app_id שנשלח בזמן השליחה. ברירת המחדל היא 1. | ➖ |
service_type | string | הערוץ שהנפיק את הקוד, sms או whatsapp. ברירת המחדל היא sms. | ➖ |
דוגמת בקשה
<?xml version="1.0" encoding="UTF-8"?>
<validate_otp>
<user>
<username>Leeroy</username>
</user>
<phone>5xxxxxxxx</phone>
<app_id>1</app_id>
<code>407526</code>
<service_type>sms</service_type>
</validate_otp>{
"validate_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms"
}
}curl --location 'https://my.textme.co.il/api' \
--header "Authorization: Bearer $TEXTME_API_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"validate_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms"
}
}'// 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({
validate_otp: {
user: {
username: 'Leeroy',
},
phone: '5xxxxxxxx',
app_id: '1',
code: '407526',
service_type: 'sms',
},
}),
})
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' => [
'validate_otp' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => '5xxxxxxxx',
'app_id' => '1',
'code' => '407526',
'service_type' => 'sms',
],
],
]);
$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', [
'validate_otp' => [
'user' => [
'username' => 'Leeroy',
],
'phone' => '5xxxxxxxx',
'app_id' => '1',
'code' => '407526',
'service_type' => 'sms',
],
])
->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={
"validate_otp": {
"user": {
"username": "Leeroy",
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms",
},
},
)
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{
"validate_otp": map[string]any{
"user": map[string]any{
"username": "Leeroy",
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms",
},
})
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 TextMeOtpValidate {
public static void main(String[] args) throws Exception {
String body = """
{
"validate_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms"
}
}
""";
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+ using System.Net.Http
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
var payload = """
{
"validate_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms"
}
}
""";
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({
"validate_otp" => {
"user" => {
"username" => "Leeroy",
},
"phone" => "5xxxxxxxx",
"app_id" => "1",
"code" => "407526",
"service_type" => "sms",
},
})
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!({
"validate_otp": {
"user": {
"username": "Leeroy"
},
"phone": "5xxxxxxxx",
"app_id": "1",
"code": "407526",
"service_type": "sms"
}
}))
.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"?>
<sms>
<status>0</status>
<message>The code successfully validated</message>
</sms>{
"status": 0,
"message": "The code successfully validated"
}שגיאות
| Status | מתי |
|---|---|
12 | הקוד לא אומת. המשמעות המתועדת של 12 בפעולה הזו היא Unverified code: קוד שגוי, קוד שפג תוקפו, או ניסיונות שנגמרו. |
2 | חסר אלמנט חובה; ה-message מציין איזה. |
סטטוס 12 הוא זה שצריך להתנות עליו
ל-12 שתי משמעויות שאינן קשורות, תלוי בפעולה: אין מספיק כסף בשליחת הודעה, וקוד לא מאומת כאן. קראו אותו מול הקריאה שביצעתם, מעולם לא בפני עצמו. ראו קודי סטטוס.
הערות על השדות
app_id מפריד בין האפליקציות שלכם
חשבון TextMe אחד יכול לשרת כמה מוצרים. מתן app_id נפרד לכל אחד שומר על עצמאות הקודים, כך שקוד שהונפק לאפליקציה 1000 אינו ניתן לאימות מול אפליקציה 1001, גם עבור אותו מספר טלפון.
הערך חייב להיות זהה בין send_otp ל-validate_otp. אי-התאמה אינה ניתנת להבחנה מקוד שגוי: תקבלו סטטוס 12.
כוונו את max_tries ואת valid_time יחד
ברירת המחדל היא שלושה ניסיונות בתוך חמש דקות. שניהם מגבילים את אותו סיכון משני כיוונים:
valid_time(1 עד 15 דקות) מגביל כמה זמן קוד שדלף נשאר שימושי. קצר יותר בטוח יותר, אבל קצר מדי ומשתמשים שעוברים לאפליקציה אחרת לקרוא את ה-SMS יחזרו לקוד שפג.max_tries(3 עד 5) מגביל ניחושים. קוד בן שש ספרות עם חמישה ניסיונות בטוח בהחלט.
הניסיונות נספרים בצד השרת, כך שאינכם צריכים לעקוב אחריהם.
כתבו את ההודעה כך שהקוד יימצא
text חייב להכיל [code]. אם תשמיטו אותו, הנמען יקבל הודעה בלי קוד בתוכה.
שימו את הקוד בתחילת ההודעה ושמרו על נוסח פשוט, כי מכשירים ומנהלי סיסמאות מזהים קודים טוב יותר בהודעות קצרות. אם אתם משתמשים ב-SMS Retriever של Google, שדה tag בשליחת sms רגילה הוא המנגנון לתחילית <#>; ל-send_otp אין מקבילה, ולכן תהליך שזקוק לזה צריך לשלוח את הקוד עם sms ולבצע אימות עצמאי.
מה זה מחליף
בלי שתי הפעולות האלה הייתם שולחים קוד עם sms, שומרים אותו בעצמכם, מפקיעים אותו בעצמכם וסופרים ניסיונות בעצמכם. send_otp מעבירה את כל זה לצד השרת: יצירה, שמירה, הפקעה וספירת ניסיונות. אתם עדיין מקבלים את הקוד בתשובה, כך שכלי תמיכה יכול להציג אותו אם עמדת הרגולציה שלכם מאפשרת, אבל התייחסו לזה כבחירה מודעת ולא כברירת מחדל.
מה לא מכוסה כאן
TextMe מתעדת גם קריאת OTP ב-WhatsApp בנקודת קצה נפרדת (whatsapp-api/send-otp-whatsapp, טוקן bearer, JSON בלבד, בלי XML), לצד API מלא ל-WhatsApp. שניהם עדיין אינם מכוסים באתר הזה. שניהם נמצאים מחוץ ל-API של ה-SMS שהעמוד הזה שייך לו, והשדה service_type שלמעלה הוא מה שמקשר בין שני ערוצי ה-OTP.

