מה השירות עושה ואיך מפעילים אותו, ולמטה הכול למפתח: קוד מוכן, ומה עושים כשמשהו לא עובד. הפירוט המלא של השדות והשגיאות נמצא במדריך העיון.
כשמישהו נרשם לאתר שלכם, מזמין או מתחבר, אפשר לוודא שמספר הטלפון שהוא נתן באמת שלו: הוא מקבל מסרון עם קוד של 6 ספרות ומקליד אותו באתר. Meser 10 Verify עושה את כל זה בשבילכם: יוצר את הקוד, שולח אותו ובודק שהוקלד נכון.
פחות הרשמות מזויפות והזמנות סרק, ומספרי טלפון אמיתיים ברשימה שלכם.
כל קוד הוא מסרון רגיל מחבילת המסרונים שלכם. אין תשלום נוסף.
לא צריך מפתח ולא צריך את העמוד הזה. יש תוסף מוכן שעושה את זה בכמה קליקים: תוסף OTP ל-WordPress.
לפני שעולים לאוויר מקבלים מאיתנו גם אסימון בדיקה. איתו אפשר לנסות את הכול בלי שיישלח מסרון ובלי חיוב.
באייפון ובאנדרואיד הטלפון מציע את הקוד מהמסרון ומכניס אותו לאתר שלכם בלחיצה אחת, בלי שהמשתמש יקליד. זה עובד באתר שהכתובת שלו רשומה אצלנו.
כותבים לתמיכה עם מספר החשבון ומבקשים להפעיל את Verify. מקבלים אסימון שמתחיל ב-vt_. שומרים אותו בשרת במשתנה סביבה, למשל MESER10_VERIFY_TOKEN, ליד MESER10_API_KEY.
אם המפתח של החשבון נדחה בכניסה, השליחות נעצרות ל-15 דקות ומתקבל key_refused. הבדיקות ממשיכות לעבוד, ואחרי שמתקנים את המפתח השליחות חוזרות לבד. לכן לפני החיבור בודקים שהמפתח עובד, עם קריאת הבדיקה שבהתחלה המהירה של ה-API. אם האסימון הושבת, מתקנים את המפתח ופונים לתמיכה להפעלה מחדש.
/v1/send ושומר את ה-id שחזר, למשל בסשן של המשתמש./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 לכתיבת קוד, ולקבל את כל השדות והשגיאות.
בקשו מהתמיכה אסימון בדיקה (מתחיל ב-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 תווים עם עברית), אז שמרו על נוסח קצר.
בודקים מה חזר מ-/v1/send. send_failed: בשליחה הראשונה של מפתח זו תשובה אחת לשלוש סיבות, מפתח שנדחה, שולח לא מאומת או אין יתרה. no_credits: נגמרה יתרת המסרונים. sender_not_verified: השולח לא מאומת. too_soon: ממתינים 30 שניות. phone_rate_limited: היו יותר מדי שליחות לאותו מספר. "ok":true אומר שהמסרון התקבל לשליחה; אם הוא לא הגיע, מוודאים שהמספר נייד ישראלי תקין.
ה-API של מסר 10 דחה את המפתח של החשבון. השליחות נעצרות ל-15 דקות (יותר אם זה חוזר) וחוזרות לבד, והבדיקות ממשיכות לעבוד. מתקנים את המפתח בהגדרות החשבון.
האסימון חסר, שגוי או מושבת. בודקים את הכותרת X-Verify-Token, ואם צריך פונים לתמיכה.
השירות עוצר שליחות כדי להגן על כל החשבונות, משנייה ועד 15 דקות. ממתינים את מספר השניות שב-retry_after ומנסים שוב.
לא ברור אם המסרון יצא. שומרים את ה-id שבתשובה ונותנים למשתמש להקליד את הקוד. לא שולחים קוד חדש מיד.
wrong_code עם attempts_left. אחרי 5 ניסיונות הבקשה נחסמת (too_many_attempts או blocked) ושולחים קוד חדש. expired: התוקף עבר או שנשלח מאז קוד חדש. phone_mismatch: המספר בבדיקה שונה מהמספר שקיבל את הקוד. already_used: הקוד כבר אומת. not_found: בודקים שהבדיקה נשלחת עם אותו מפתח של השליחה.
Verify פונה מכתובות של Cloudflare, ולכן חשבון שהגביל את ה-API לכתובות מסוימות לא יכול להשתמש בו. הסימן: השליחה הראשונה נכשלת עם key_refused. פונים לתמיכה.
חמש דקות כברירת מחדל. אפשר לקבוע בין דקה ל-15 דקות בשדה ttl בשליחה.
לא. Verify שולח למספרי נייד ישראליים בלבד.
המסרון נשלח דרך חשבון מסר 10 שלכם ומחויב שם כמו כל מסרון.
פונים לתמיכה. מבטלים את האסימון הישן ומנפיקים חדש.