03-7440020 +1 917-277-5362 +44 203 146-8524
כניסת לקוחות
מסר10
פתחו חשבון חינם
הפיצ'רים של מסר 10

OTP: קוד אימות חד-פעמי ב-SMS

קריאת HTTP אחת שולחת קוד אימות למספר ישראלי. בלי SDK, בלי תור, בלי הגדרה מוקדמת חוץ מאישור שם השולח.

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

קריאה אחת, בלי להתקין שום דבר

כך נראית שליחה של קוד אימות. אפשר להדביק את זה לטרמינל ולראות את התשובה:

curl -sS -X POST "https://heb.mesereser.com/Services/JsonServices.aspx?f=SendSingleSmsMessage" \
  -H "ApiKey: $MESER10_API_KEY" \
  -H "Content-Type: application/json; charset=utf-8" \
  -H "User-Agent: my-app/1.0" \
  -d '{"ToPhone":"0501234567","MessageBody":"Your code is 481902.","FromName":"MyShop"}'

{"ErrorCode":0,"Result":"","MessageID":0}

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

curl -sS "https://heb.mesereser.com/Services/JsonServices.aspx?f=GetContactStatus&email=nobody.probe@example.invalid" \
  -H "ApiKey: $MESER10_API_KEY" \
  -H "User-Agent: my-app/1.0"

{"ErrorCode":0,"Result":"Call successful","StatusID":0}

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

אותה קריאה בארבע שפות

בלי ספרייה ובלי תלות. שימו לב שבכל אחת מהן נשלחת כותרת User-Agent, וזה לא קוסמטי.

// PHP
$ch = curl_init('https://heb.mesereser.com/Services/JsonServices.aspx?f=SendSingleSmsMessage');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'ApiKey: ' . getenv('MESER10_API_KEY'),
        'Content-Type: application/json; charset=utf-8',
        'User-Agent: my-app/1.0',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'ToPhone'     => $phone,
        'MessageBody' => "קוד האימות שלך הוא {$code}",
        'FromName'    => 'MyShop',
    ], JSON_UNESCAPED_UNICODE),
]);
$body = json_decode(curl_exec($ch), true);
$ok   = (string) $body['ErrorCode'] === '0';
// Node 18+
const res = await fetch(
  'https://heb.mesereser.com/Services/JsonServices.aspx?f=SendSingleSmsMessage',
  {
    method: 'POST',
    headers: {
      ApiKey: process.env.MESER10_API_KEY,
      'Content-Type': 'application/json; charset=utf-8',
      'User-Agent': 'my-app/1.0',
    },
    body: JSON.stringify({
      ToPhone: phone,
      MessageBody: `קוד האימות שלך הוא ${code}`,
      FromName: 'MyShop',
    }),
  },
);
const body = await res.json();
const ok = String(body.ErrorCode) === '0';
# Python
import os, requests

res = requests.post(
    "https://heb.mesereser.com/Services/JsonServices.aspx",
    params={"f": "SendSingleSmsMessage"},
    headers={
        "ApiKey": os.environ["MESER10_API_KEY"],
        # urllib's default signature is refused. requests passes, but set
        # something of your own anyway.
        "User-Agent": "my-app/1.0",
    },
    json={
        "ToPhone": phone,
        "MessageBody": f"קוד האימות שלך הוא {code}",
        "FromName": "MyShop",
    },
    timeout=20,
)
ok = str(res.json().get("ErrorCode")) == "0"
// C# - one HttpClient for the lifetime of the application, not one per call
var payload = JsonSerializer.Serialize(new
{
    ToPhone     = phone,
    MessageBody = $"קוד האימות שלך הוא {code}",
    FromName    = "MyShop",
});

using var request = new HttpRequestMessage(
    HttpMethod.Post,
    "https://heb.mesereser.com/Services/JsonServices.aspx?f=SendSingleSmsMessage")
{
    Content = new StringContent(payload, Encoding.UTF8, "application/json"),
};
request.Headers.Add("ApiKey", apiKey);
request.Headers.Add("User-Agent", "my-app/1.0");

using var response = await http.SendAsync(request);
var body = JsonDocument.Parse(await response.Content.ReadAsStringAsync());

ה-API מתועד גם כמפרט OpenAPI 3.1 וכאוסף Postman, כך שאפשר להפיק קליינט בשפה שלכם במקום להעתיק את הקוד שלמעלה.

שלושה דברים לפני שבונים על זה מסך התחברות

קוראים את ErrorCode, לא את קוד ה-HTTP. כל קריאה חוזרת ב-200 גם כשהיא נכשלה, כולל מפתח שנדחה. בנוסף ErrorCode מוחזר כמספר בחלק מהפונקציות וכמחרוזת באחרות, ולכן משווים אחרי נרמול ולא ישירות.

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

שולחים כותרת User-Agent. השרתים יושבים מאחורי Cloudflare Browser Integrity Check, שקוראת את הכותרת וחוסמת חתימות ברירת מחדל של ספריות HTTP: Java/1.8.0_241 מקבל 403, ו-Python-urllib/3.x מקבל שגיאה 1010. כל ערך מותאם עובר, והערך עצמו לא משנה. התסמין מופיע לסירוגין, כי למערכת יש לרוב שני מסלולי קוד לאותה נקודת קצה ורק אחד מהם שולח את הכותרת.

שם השולח, וזה מה שעוצר רוב האינטגרציות הראשונות

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

FromName
  alphanumeric   up to 11 characters, A-Z a-z 0-9 and space,
                 at least one letter
  numeric        a full phone number, local or E.164

  MyShop           ok
  Meser10 Ltd      ok, exactly 11
  Meser10 Israel   rejected, 14 characters
  מסר 10           rejected, Hebrew is not a sender name
  0501234567       ok

שם ארוך מ-11 תווים אינו נחתך, הקריאה פשוט נדחית. מגבלת 11 התווים היא כלל של רשתות ה-GSM ולא שלנו, והיא זהה אצל כל הספקים. התמיכה בשם שולח טקסטואלי גם משתנה בין מדינות: בארצות הברית ובקנדה היא אינה קיימת ובמקומה משתמשים במספר.

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

עברית מכפילה את עלות ההודעה

אות עברית אחת כלשהי בהודעה מעבירה את כולה ל-Unicode, ואז חלק בודד מחזיק 70 תווים במקום 160. הודעה ארוכה יותר נשלחת כמספר חלקים ומחויבת לפי מספרם. לכן שווה למדוד לפני שמייצרים את הנוסח, במיוחד כשהקוד עצמו משתנה באורך.

בפועל, נוסח כמו "קוד האימות שלך הוא 481902. הקוד תקף ל-5 דקות." הוא 46 תווים, כלומר חלק אחד. כל תוספת של משפט אחד בעברית כבר מכניסה את ההודעה לחלק שני.

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

וגם קוד אימות במייל

אותו שער שולח גם מייל טרנזקציוני בודד, דרך SendSingleEMailMessage. שווה לדעת מה הפונקציה הזאת אינה מקבלת לפני שמנתבים אליה הודעה: אין כתובת From אלא שם תצוגה בלבד, אין CC ואין BCC, אין קבצים מצורפים, ונמען אחד בכל קריאה. הפירוט בעמוד מייל טרנזקציוני, ולמי שמעדיף SMTP רגיל יש גם ממשק SMTP.

שאלות נפוצות

מה צריך כדי לשלוח קוד אימות ראשון?

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

למה קריאה תקינה מחזירה ErrorCode 4?

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

האם יש סביבת בדיקות?

אין sandbox נפרד. הדבר הקרוב לזה הוא קריאת GetContactStatus לכתובת שאינה קיימת בחשבון, שמוכיחה שהמפתח נקרא בלי ליצור דבר ובלי לשלוח דבר. שליחה אמיתית תמיד מגיעה לנמען אמיתי ומחייבת את החשבון.

מה קורה אם מנסים שוב אחרי כשל?

תלוי בסוג הכשל. ErrorCode 3 הוא שגיאה זמנית ואפשר לנסות פעם אחת נוספת. ErrorCode 1, כלומר כשל הזדהות, אסור לנסות שוב: ניסיונות חוזרים חוסמים את כתובת ה-IP למשך שעות. ErrorCode 4 לא ישתנה בניסיון נוסף, כי הוא אומר שפרמטר שגוי.

מוכנים לשלוח את הקוד הראשון?

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

פתחו חשבון חינם