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

Meser 10 Verify: קוד אימות ב-SMS לאתר שלכם

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

מה זה, במילים פשוטות

כשמישהו נרשם לאתר שלכם, מזמין או מתחבר, אפשר לוודא שמספר הטלפון שהוא נתן באמת שלו: הוא מקבל מסרון עם קוד של 6 ספרות ומקליד אותו באתר. Meser 10 Verify עושה את כל זה בשבילכם: יוצר את הקוד, שולח אותו ובודק שהוקלד נכון.

למה זה טוב

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

כמה זה עולה

כל קוד הוא מסרון רגיל מחבילת המסרונים שלכם. אין תשלום נוסף.

יש לכם אתר WordPress?

לא צריך מפתח ולא צריך את העמוד הזה. יש תוסף מוכן שעושה את זה בכמה קליקים: תוסף OTP ל-WordPress.

בודקים בלי לשלם

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

הקוד מתמלא לבד

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

מה אתם צריכים לעשות

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

1. לפני שמתחילים

  1. חשבון במסר 10 ומפתח API, שמנפיקים בהגדרות המתקדמות של החשבון.
  2. שם שולח מאומת באותיות לטיניות (2 עד 11 אותיות, ספרות או רווחים, בלי עברית) או מספר שולח מאומת: אימות שם שולח.
  3. יתרת מסרונים בחשבון: בדיקת יתרת מסרונים.
  4. שרת שלכם שממנו יוצאות הקריאות. המפתח והאסימון אסור שיגיעו לדפדפן או לאפליקציה.

2. מקבלים אסימון גישה

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

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

3. איך זה עובד באתר שלכם

  1. המשתמש מקליד מספר נייד.
  2. השרת שלכם קורא ל-/v1/send ושומר את ה-id שחזר, למשל בסשן של המשתמש.
  3. המשתמש מקליד את הקוד שקיבל ב-SMS.
  4. השרת קורא ל-/v1/check עם ה-id והקוד. אם verified הוא true, המספר מאומת.

Node.js:

// Node.js 18+, ES module (.mjs)
const H = {
  "Content-Type": "application/json",
  "ApiKey": process.env.MESER10_API_KEY,
  "X-Verify-Token": process.env.MESER10_VERIFY_TOKEN
};
async function verifyCall(path, body) {
  const r = await fetch("https://verify.mesereser.com/v1/" + path, { method: "POST", headers: H, body: JSON.stringify(body) });
  return r.json();
}

// 1. Send a code
const s = await verifyCall("send", { phone: "0501234567", from: "MyShop", lang: "he" });
if (!s.ok && s.error !== "upstream_uncertain") throw new Error("send failed: " + s.error);
const requestId = s.id;   // keep it with the user's session

// 2. Check what the user typed
// use the same ApiKey and token as the send
const c = await verifyCall("check", { id: requestId, code: userInput, phone: "0501234567" });
if (c.verified === true) {
  // mark the number as verified
} else {
  // not verified: c.error tells why (wrong_code, expired ...), c.attempts_left how many tries remain
}

PHP:

<?php
// PHP 7.4+ with the curl extension
function verify_call(string $path, array $body): array {
    $ch = curl_init("https://verify.mesereser.com/v1/" . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_HTTPHEADER     => [
            "Content-Type: application/json",
            "ApiKey: " . getenv("MESER10_API_KEY"),
            "X-Verify-Token: " . getenv("MESER10_VERIFY_TOKEN"),
        ],
        CURLOPT_POSTFIELDS     => json_encode($body),
    ]);
    $data = json_decode((string) curl_exec($ch), true);
    curl_close($ch);
    return is_array($data) ? $data : [];
}

// 1. Send a code
$s = verify_call("send", ["phone" => "0501234567", "from" => "MyShop", "lang" => "he"]);
if (empty($s["ok"]) && ($s["error"] ?? "") !== "upstream_uncertain") {
    throw new RuntimeException("send failed: " . ($s["error"] ?? "no response"));
}
session_start();
$_SESSION["verify_id"] = $s["id"];

// 2. Check what the user typed
// use the same ApiKey and token as the send
$c = verify_call("check", ["id" => $_SESSION["verify_id"], "code" => $_POST["code"], "phone" => "0501234567"]);
if (($c["verified"] ?? false) === true) {
    // mark the number as verified
} else {
    // not verified: $c["error"] tells why (wrong_code, expired ...), $c["attempts_left"] how many tries remain
}

Python:

# Python 3.8+  (pip install requests)
import os
import requests

API = "https://verify.mesereser.com/v1/"
HEADERS = {
    "ApiKey": os.environ["MESER10_API_KEY"],
    "X-Verify-Token": os.environ["MESER10_VERIFY_TOKEN"],
}

def verify_call(path, body):
    r = requests.post(API + path, json=body, headers=HEADERS, timeout=15)
    return r.json()

# 1. Send a code
s = verify_call("send", {"phone": "0501234567", "from": "MyShop", "lang": "he"})
if not s.get("ok") and s.get("error") != "upstream_uncertain":
    raise RuntimeError("send failed: " + str(s.get("error")))
request_id = s["id"]   # keep it with the user's session

# 2. Check what the user typed
# use the same ApiKey and token as the send
c = verify_call("check", {"id": request_id, "code": user_input, "phone": "0501234567"})
if c.get("verified") is True:
    pass   # mark the number as verified
else:
    pass   # not verified: c.get("error") tells why (wrong_code, expired ...), c.get("attempts_left") how many tries remain

cURL (שורת פקודה):

# 1. Send a code
curl -sS -X POST "https://verify.mesereser.com/v1/send" \
  -H "Content-Type: application/json" \
  -H "ApiKey: $MESER10_API_KEY" \
  -H "X-Verify-Token: $MESER10_VERIFY_TOKEN" \
  -d '{"phone":"0501234567","from":"MyShop","lang":"he"}'
# {"ok":true,"id":"<request-id>","expires_in":300,"phone":"050*****67"}

# 2. Check the code the user typed (same ApiKey and token)
curl -sS -X POST "https://verify.mesereser.com/v1/check" \
  -H "Content-Type: application/json" \
  -H "ApiKey: $MESER10_API_KEY" \
  -H "X-Verify-Token: $MESER10_VERIFY_TOKEN" \
  -d '{"id":"<request-id>","code":"<code>","phone":"0501234567"}'
# {"ok":true,"verified":true,"phone":"050*****67"}

C# (.NET):

// .NET 6+ console app (top-level statements)
using System.Net.Http.Json;
using System.Text.Json;

var http = new HttpClient { BaseAddress = new Uri("https://verify.mesereser.com/v1/"), Timeout = TimeSpan.FromSeconds(15) };
http.DefaultRequestHeaders.Add("ApiKey", Environment.GetEnvironmentVariable("MESER10_API_KEY"));
http.DefaultRequestHeaders.Add("X-Verify-Token", Environment.GetEnvironmentVariable("MESER10_VERIFY_TOKEN"));

async Task<JsonElement> VerifyCall(string path, object body)
{
    var r = await http.PostAsJsonAsync(path, body);
    return await r.Content.ReadFromJsonAsync<JsonElement>();
}
static bool IsTrue(JsonElement e, string name) => e.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.True;
static string? Text(JsonElement e, string name) => e.TryGetProperty(name, out var v) && v.ValueKind == JsonValueKind.String ? v.GetString() : null;

// 1. Send a code
var s = await VerifyCall("send", new { phone = "0501234567", from = "MyShop", lang = "he" });
if (!IsTrue(s, "ok") && Text(s, "error") != "upstream_uncertain")
    throw new Exception("send failed: " + Text(s, "error"));
var requestId = Text(s, "id");   // keep it with the user's session

// 2. Check what the user typed
// use the same ApiKey and token as the send
var c = await VerifyCall("check", new { id = requestId, code = userInput, phone = "0501234567" });
if (IsTrue(c, "verified"))
{
    // mark the number as verified
}
else
{
    // not verified: Text(c, "error") tells why (wrong_code, expired ...); c.GetProperty("attempts_left") how many tries remain
}

OpenAPI: תיאור מלא של ה-API נמצא בקובץ openapi.json. אפשר לטעון אותו ל-Postman, ל-Swagger UI או לכלי AI לכתיבת קוד, ולקבל את כל השדות והשגיאות.

בדיקה בלי לשלוח SMS

בקשו מהתמיכה אסימון בדיקה (מתחיל ב-vt_test_) ושימו אותו ב-X-Verify-Token במקום האסימון הרגיל. לא נשלח שום מסרון ושום דבר לא מחויב. תשובת השליחה מחזירה גם את הקוד ואת נוסח המסרון המדויק, כך שאפשר להריץ את כל התהליך בבדיקות שלכם:

{"ok":true,"id":"<request-id>","expires_in":300,"phone":"050*****67","test":true,"test_code":"481902","message":"481902 הוא קוד האימות שלך"}

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

הקוד מתמלא לבד

הוסיפו לשליחה "autofill":"web". המסרון יסתיים בשורה שהטלפון משתמש בה כדי למלא את הקוד באתר שלכם לבד (Safari באייפון ובמק, Chrome באנדרואיד):

{"phone":"0501234567","from":"MyShop","lang":"he","autofill":"web"}
481902 הוא קוד האימות שלך

@shop.co.il #481902

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

<input name="code" autocomplete="one-time-code" inputmode="numeric">
<script>
// Chrome on Android (WebOTP); Safari uses autocomplete="one-time-code" by itself
if ("OTPCredential" in window) {
  navigator.credentials.get({ otp: { transport: ["sms"] } })
    .then(otp => { document.querySelector("[name=code]").value = otp.code; })
    .catch(() => {});
}
</script>

לאפליקציית אנדרואיד שמשתמשת ב-SMS Retriever API, שלחו "autofill":"android" ומסרו לתמיכה את ה-hash של האפליקציה (11 תווים). השורה הנוספת נספרת במגבלה של מסרון אחד (70 תווים עם עברית), אז שמרו על נוסח קצר.

4. פתרון בעיות

הקוד לא מגיע

בודקים מה חזר מ-/v1/send. send_failed: בשליחה הראשונה של מפתח זו תשובה אחת לשלוש סיבות, מפתח שנדחה, שולח לא מאומת או אין יתרה. no_credits: נגמרה יתרת המסרונים. sender_not_verified: השולח לא מאומת. too_soon: ממתינים 30 שניות. phone_rate_limited: היו יותר מדי שליחות לאותו מספר. "ok":true אומר שהמסרון התקבל לשליחה; אם הוא לא הגיע, מוודאים שהמספר נייד ישראלי תקין.

key_refused

ה-API של מסר 10 דחה את המפתח של החשבון. השליחות נעצרות ל-15 דקות (יותר אם זה חוזר) וחוזרות לבד, והבדיקות ממשיכות לעבוד. מתקנים את המפתח בהגדרות החשבון.

not_enabled

האסימון חסר, שגוי או מושבת. בודקים את הכותרת X-Verify-Token, ואם צריך פונים לתמיכה.

temporarily_unavailable

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

upstream_uncertain

לא ברור אם המסרון יצא. שומרים את ה-id שבתשובה ונותנים למשתמש להקליד את הקוד. לא שולחים קוד חדש מיד.

הקוד נדחה

wrong_code עם attempts_left. אחרי 5 ניסיונות הבקשה נחסמת (too_many_attempts או blocked) ושולחים קוד חדש. expired: התוקף עבר או שנשלח מאז קוד חדש. phone_mismatch: המספר בבדיקה שונה מהמספר שקיבל את הקוד. already_used: הקוד כבר אומת. not_found: בודקים שהבדיקה נשלחת עם אותו מפתח של השליחה.

החשבון מגביל כתובות IP ל-API

Verify פונה מכתובות של Cloudflare, ולכן חשבון שהגביל את ה-API לכתובות מסוימות לא יכול להשתמש בו. הסימן: השליחה הראשונה נכשלת עם key_refused. פונים לתמיכה.

שאלות נפוצות

כמה זמן הקוד תקף?

חמש דקות כברירת מחדל. אפשר לקבוע בין דקה ל-15 דקות בשדה ttl בשליחה.

אפשר לשלוח למספרים בחו"ל?

לא. Verify שולח למספרי נייד ישראליים בלבד.

כמה זה עולה?

המסרון נשלח דרך חשבון מסר 10 שלכם ומחויב שם כמו כל מסרון.

האסימון נחשף. מה עושים?

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