Skip to content

    Arabic or English · ↑↓ to move · Enter to open · Esc to close

    العربية
    On this page

    OTP done right

    Send one-time codes from your own number: Mursilat generates and hashes the code, uses a fixed safe text, and limits attempts and recipients.

    POST /v2/otp sends a verification code; POST /v2/otp/{otpId}/verify checks what the person typed. You never handle or store the code: Mursilat generates it with a secure random generator and keeps only a keyed hash.

    curl -X POST "https://mursilat.com/api/v2/otp" \
      -H "Authorization: Bearer $WASLA_API_KEY" \
      -H "Idempotency-Key: order-1042-confirm" \
      -H "Content-Type: application/json" \
      -d '{
      "numberId": "cm1abcd2345efgh6789ijkl",
      "to": "201001234567",
      "length": 6,
      "ttlSeconds": 300,
      "maxAttempts": 5,
      "app": "متجر النور",
      "copyButton": true
    }'

    Fixed templates

    The text is fixed and localized, so the OTP endpoint can never relay arbitrary messages or phishing links. Only the code, the validity in minutes and your app name are filled in:

    localeText
    ar (default)Text«كود التحقق لـ {app}: {code} — صالح لمدة {minutes} دقيقة. متشاركهوش مع أي حد.»
    enText“Your verification code for {app}: {code} — Valid for {minutes} minutes. Do not share it with anyone.”

    app accepts letters, digits and spaces (≤ 30) — no links, no domain endings such as com or sa, no link services, no runs of 6+ digits. copyButton: true adds a “Copy code” button.

    Limits

    LimitValue
    Code length / validity / attemptsValue4–8 digits · 60–900 s · 1–10 attempts
    Codes per recipientValue5 per hour
    Different recipients per accountValue200 per hour (OTP_ACCOUNT_RATE_LIMITED)
    Verify callsValue60 per key per minute
    Number Shield OTP classValue30 per hour and 300 per day per number, 3–5 s pacing
    QuotaValue1 message unit, refunded if the send fails

    Opted-out recipients are refused. OTP rows are deleted after 7 days; the recipient is stored masked.

    Verifying

    Send the code as a string (leading zeros matter). Each call spends one attempt before the constant-time comparison; at maxAttempts the OTP locks. valid: false comes with a reason: INVALID_CODE, EXPIRED, TOO_MANY_ATTEMPTS or ALREADY_VERIFIED. The otp.verified webhook (without the code) fires on success.

    curl -X POST "https://mursilat.com/api/v2/otp/otp_8f2c1d9a7b3e4f56a1b2c3d4/verify" \
      -H "Authorization: Bearer $WASLA_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
      "code": "048213"
    }'

    Deliverability

    Send OTPs from a number people already know — ideally a dedicated one, not the number you use for campaigns, so marketing reports never block your logins. See Using a dedicated business number.