שגיאות וסטטוסים
TextMe מדווחת על כשלים בגוף של תשובת HTTP 200 רגילה לחלוטין. יש מבנה אחד לכולם, ושדה אחד שעליו מתנים את הלוגיקה.
מעטפת השגיאה
{
"status": 4,
"message": "Not enough credit"
}| שדה | משמעות |
|---|---|
status | 0 בהצלחה; כל ערך אחר הוא כשל. |
message | הסבר קריא לאדם. בסטטוס 2 הוא מציין את השדה החסר. |
אף פעם לא להתנות על סטטוס ה-HTTP לבדו
כשלי אימות, כשלי ולידציה וכשלי מכסה — כולם מגיעים כ-HTTP 200. לקוח שבודק רק את response.ok יתייחס לכל אחד מהם כאל שליחה מוצלחת.
כל דוגמת קוד באתר הזה עושה את אותם שלושה צעדים: שולחת, מפענחת, ואז משווה את status ל-0 לפני שהיא סומכת על כל דבר אחר בתשובה.
שני סטטוסים, שני אוצרות מילים
המילה סטטוס מופיעה בשני מקומות שאינם קשורים זה לזה, ובלבול ביניהם היא טעות האינטגרציה הנפוצה ביותר.
| איפה | אוצר המילים | |
|---|---|---|
| סטטוס הבקשה | status ברמה העליונה בכל תשובה | האם ה-API קיבל את הקריאה? — קודי סטטוס |
| סטטוס המסירה | status בתוך כל רשומה ב-transactions[] של דוח מסירה | מה קרה להודעה במכשיר? — סטטוסי מסירה |
דוח מסירה יכול להחזיר status: 0 ברמה העליונה (הדוח הופק) בעוד שרשומות בודדות בתוכו נושאות 102 (נמסר) או 1 (נכשל). מדובר בשני סולמות שונים שבמקרה חולקים שם שדה.
הצלחה חלקית
כמה פעולות מקבלות אצווה ומעבדות אותה שורה-שורה. הן מחזירות status: 0 — הפעולה רצה — יחד עם רשימת errors שמתארת את השורות שלא נכנסו.
{
"status": 0,
"message": "The phone numbers have been added successfully",
"errors": [
"The phone 05XXXXXXXX is already on the contact list and therefore not added"
]
}הפעולות שמתנהגות כך הן כתיבות לרשימות תפוצה (newCL, removeCL, addNumCL, rmNumCL). התייחסות ל-status: 0 שלהן כאל "הכול עבד" תשמיט נמענים בשקט — קראו את errors בכל פעם שהוא קיים.
סוגי כשלים
פרטי גישה והרשאות — 3, 10, 11, 504, 511. הטוקן שגוי, פג תוקף, לא תואם, או שהחשבון אינו רשאי לבצע את הפעולה. ניסיון חוזר לא יעזור; ראו אימות.
בקשה פגומה — 1, 2, 997. המסמך לא נפרסר, חסר שדה חובה, או שאלמנט השורש אינו פעולה. דטרמיניסטי: אותו גוף בקשה ייכשל תמיד. תקנו את הבקשה; נקודת הקצה לבדיקות היא הדרך הזולה לעשות זאת.
ערכים שנדחו — 9, 714, 980, 986, 989, 990, 991, 992, 993, 995, 996. שדה מסוים נכשל בוולידציה — מספר קצר מדי, הודעה ארוכה מדי, ערך add_unsubscribe שאינו 2 או 3. ה-message מציין איזה.
מצב החשבון — 4 (אין יתרה), 12 (אין מספיק כסף), 5 (אין הרשאת שליחה בשעה הזו), 515 (שולח לא מאומת). אין שום בעיה בבקשה; יש בעיה בחשבון. הקריאות האלה עשויות להצליח בהמשך, אחרי טעינת יתרה, בשעה אחרת, או לאחר אימות השולח.
לא נשאר למי לשלוח — 8 (כל היעדים חסומים), 715 (כל היעדים סוננו על ידי temp_bl), 988 (רשימת התפוצה אינה קיימת). הקריאה הייתה תקינה ופשוט לא נשארו נמענים. כדאי לתעד את אלה בנפרד: בדרך כלל הבעיה היא בקהל, לא בקוד.
בצד השרת — 6, 970, 999. כשל תהליך. אפשר לנסות שוב פעם אחת עם השהיה; אם זה חוזר, פנו לתמיכה.
ניסיונות חוזרים בבטחה
אין מנגנון idempotency key. שליחה שנשלחת פעמיים היא שתי שליחות, ושתיהן יימסרו וייגבו.
- אף פעם לא לנסות שליחה מחדש בעיוורון. אם
smsאוbulkנכשלים בטיים-אאוט בשכבת התעבורה, אינכם יודעים אם ההודעה יצאה. פתרו זאת בקריאה ולא בכתיבה: תנוidלכל יעד (ראו דוחות מסירה) ובדקו בדוח לפני שאתם שולחים שוב. - קריאות בטוחות לחזרה.
balance,dlr,dlrByDate,incoming,getCL,getVerifiedPhonesושאר פעולות הקריאה אינן משנות דבר. - כתיבות אינן אידמפוטנטיות. קריאה כפולה ל-
newCLיוצרת שתי רשימות;addNumBLפעמיים אינה מזיקה, אבלupdateAmountSubפעמיים מעבירה קרדיט פעמיים. - השהו לפני ניסיון חוזר ב-
6וב-999. נסו שוב לאחר השהיה קצרה ולא מיד.
דוגמה מלאה
התבנית שכל דוגמה באתר הזה משתמשת בה, במלואה:
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(payload),
})
// שכבת התעבורה נכשלת רק לעיתים רחוקות, אבל כשזה קורה אינכם יודעים אם
// ההודעה נשלחה — אין לנסות שליחה מחדש כאן.
if (!response.ok) {
throw new Error(`TextMe transport error: HTTP ${response.status}`)
}
const result = await response.json()
// זו הבדיקה שקובעת.
if (Number(result.status) !== 0) {
throw new TextMeError(result.status, result.message)
}
// פעולת אצווה יכולה להצליח בסך הכול ובכל זאת להשמיט שורות.
for (const problem of result.errors ?? []) {
console.warn('TextMe partial failure:', problem)
}
return resultimport os
import httpx
class TextMeError(RuntimeError):
def __init__(self, status, message):
super().__init__(f"TextMe {status}: {message}")
self.status = int(status)
self.message = message
def call(payload):
response = httpx.post(
"https://my.textme.co.il/api",
headers={"Authorization": f"Bearer {os.environ['TEXTME_API_TOKEN']}"},
json=payload,
)
# כשל תעבורה משאיר שליחה במצב לא ידוע — אין לנסות אותה מחדש.
response.raise_for_status()
result = response.json()
# זו הבדיקה שקובעת.
if int(result["status"]) != 0:
raise TextMeError(result["status"], result["message"])
# פעולת אצווה יכולה להצליח בסך הכול ובכל זאת להשמיט שורות.
for problem in result.get("errors", []):
print("TextMe partial failure:", problem)
return result<?php
function textme(array $payload): array
{
$client = new \GuzzleHttp\Client([
'headers' => [
'Authorization' => 'Bearer '.getenv('TEXTME_API_TOKEN'),
'Accept' => 'application/json',
],
]);
$response = $client->post('https://my.textme.co.il/api', ['json' => $payload]);
$result = json_decode($response->getBody()->getContents(), true);
// זו הבדיקה שקובעת.
if ((int) $result['status'] !== 0) {
throw new RuntimeException("TextMe {$result['status']}: {$result['message']}");
}
// פעולת אצווה יכולה להצליח בסך הכול ובכל זאת להשמיט שורות.
foreach ($result['errors'] ?? [] as $problem) {
error_log("TextMe partial failure: {$problem}");
}
return $result;
}הטבלאות המלאות
- קודי סטטוס — כל הערכים ש-
statusברמה העליונה יכול לקבל. - סטטוסי מסירה — כל הערכים שרשומת דוח מסירה יכולה לקבל, עם תרגום לאנגלית של ההודעות בעברית.

