urmi-ai/OTP_SMS_IMPLEMENTATION.md
2026-10-02 11:22:40 +05:30

9.3 KiB
Raw Blame History

Ultronsms — URMI OTP flow (hardcoded)

Hardcoded integration for sending URMI app OTP verification SMS via Ultronsms. Parameters below were verified with live sends and delivery reports on 2026-08-30.


Overview

┌─────────────┐     generate OTP      ┌──────────────┐     SendSMS API     ┌─────────────┐
│  Your app   │ ────────────────────► │  SMS client  │ ──────────────────► │  Ultronsms  │
│  (backend)  │                       │  (this doc)  │                     │   gateway   │
└─────────────┘                       └──────────────┘                     └──────┬──────┘
       │                                    │                                      │
       │                                    │         GetDelivery API              │
       │                                    ◄──────────────────────────────────────┘
       │                                    │
       ▼                                    ▼
  Store OTP + expiry                 Delivered / Failed

Flow

  1. Generate a numeric OTP (e.g. 6 digits).
  2. Call SendSMS with the DLT-approved template text (OTP + validity substituted).
  3. Store OTP server-side with expiry; return success/failure to the client (never return the OTP in API responses if SMS is the only channel).
  4. Optionally poll GetDelivery with the returned JobId for delivery confirmation.

Hardcoded configuration

These values are fixed for the URMI OTP use case.

Setting Value
Base URL https://ultronsms.com
Username GENZENITH
Password dssdl@33
Sender ID URMIAI
Channel Trans (Transactional)
Route 2
PE ID (peid) 1701178780498045011
DLT Template ID (dlttemplateid) 1777178797989033323
DCS 0 (English)
Flash SMS 0 (normal SMS)

DLT-approved template

Registered text (placeholders {#num#} × 2):

Your URMI app verification code is {#num#}. It is valid for {#num#} minutes. Do not share it to anyone - URMI AI

Sent text (example — replace variables only):

Your URMI app verification code is 482916. It is valid for 10 minutes. Do not share it to anyone - URMI AI

The message body must match the approved template character-for-character except for the variable values.


API endpoints

Action Method URL
Send SMS GET https://ultronsms.com/api/mt/SendSMS
Delivery status GET https://ultronsms.com/api/mt/GetDelivery

Always use HTTPS. HTTP returns 301 Moved Permanently.

SendSMS query parameters

Parameter Required OTP value
user yes GENZENITH
password yes dssdl@33
senderid yes URMIAI
channel yes Trans
route yes 2
number yes E.164 without +, e.g. 916296346452
text yes Filled DLT template (see above)
peid yes 1701178780498045011
dlttemplateid yes 1777178797989033323
DCS yes 0
flashsms yes 0

GetDelivery query parameters

Parameter Required Description
user yes Same as SendSMS
password yes Same as SendSMS
jobid yes JobId from SendSMS response

Response reference

SendSMS — success

{
  "ErrorCode": "000",
  "ErrorMessage": "Done",
  "JobId": "211261464",
  "MessageData": [
    {
      "Number": "916296346452",
      "MessageId": "X4jHLUsSDUSu6cD3yodiYw",
      "Message": null
    }
  ]
}

SendSMS — common errors

ErrorCode ErrorMessage Cause
7 username or password is invalid Wrong credentials
25 NullReferenceException (server) Invalid route (e.g. UI label T_22 instead of 2)

GetDelivery — success

{
  "ErrorCode": "0",
  "ErrorMessage": "Done",
  "DeliveryReports": [
    {
      "MessageId": "X4jHLUsSDUSu6cD3yodiYw",
      "DeliveryStatus": "Delivered",
      "DeliveryDate": "2026-08-30T11:37:18.523",
      "ErrorCode": "000"
    }
  ]
}

DeliveryStatus may be Sent briefly before updating to Delivered. Poll again after 3–5 seconds if needed.


Python implementation (hardcoded)

import random
import time
from urllib.parse import urlencode
from urllib.request import urlopen

# --- Hardcoded URMI OTP config ---
ULTRONSMS_BASE = "https://ultronsms.com"
ULTRONSMS_USER = "GENZENITH"
ULTRONSMS_PASSWORD = "dssdl@33"
SENDER_ID = "URMIAI"
PE_ID = "1701178780498045011"
DLT_TEMPLATE_ID = "1777178797989033323"
OTP_VALIDITY_MINUTES = 10


def _get_json(url: str) -> dict:
    with urlopen(url, timeout=30) as resp:
        import json
        return json.loads(resp.read().decode())


def _build_url(path: str, params: dict) -> str:
    return f"{ULTRONSMS_BASE}{path}?{urlencode(params)}"


def generate_otp(length: int = 6) -> str:
    return "".join(str(random.randint(0, 9)) for _ in range(length))


def format_otp_message(otp: str, validity_minutes: int = OTP_VALIDITY_MINUTES) -> str:
    return (
        f"Your URMI app verification code is {otp}. "
        f"It is valid for {validity_minutes} minutes. "
        f"Do not share it to anyone - URMI AI"
    )


def normalize_phone(number: str) -> str:
    """Convert +91XXXXXXXXXX or 91XXXXXXXXXX to gateway format."""
    digits = "".join(c for c in number if c.isdigit())
    if len(digits) == 10:
        return f"91{digits}"
    return digits


def send_urmi_otp(mobile: str, otp: str | None = None) -> dict:
    """
    Send URMI OTP SMS. Returns gateway response including JobId.
    If otp is None, generates a new 6-digit code.
    """
    code = otp or generate_otp()
    params = {
        "user": ULTRONSMS_USER,
        "password": ULTRONSMS_PASSWORD,
        "senderid": SENDER_ID,
        "channel": "Trans",
        "route": "2",
        "DCS": "0",
        "flashsms": "0",
        "number": normalize_phone(mobile),
        "text": format_otp_message(code),
        "peid": PE_ID,
        "dlttemplateid": DLT_TEMPLATE_ID,
    }
    result = _get_json(_build_url("/api/mt/SendSMS", params))
    result["_otp"] = code  # for app storage; do not expose to client
    return result


def get_delivery(job_id: str) -> dict:
    params = {
        "user": ULTRONSMS_USER,
        "password": ULTRONSMS_PASSWORD,
        "jobid": job_id,
    }
    return _get_json(_build_url("/api/mt/GetDelivery", params))


def send_otp_and_wait_delivery(mobile: str, max_wait_seconds: int = 15) -> dict:
    """Send OTP and poll delivery until Delivered or timeout."""
    send_result = send_urmi_otp(mobile)
    if send_result.get("ErrorCode") != "000":
        return {"send": send_result, "delivery": None, "otp": send_result.get("_otp")}

    job_id = send_result["JobId"]
    deadline = time.time() + max_wait_seconds
    delivery = None
    while time.time() < deadline:
        delivery = get_delivery(job_id)
        reports = delivery.get("DeliveryReports") or []
        if reports and reports[0].get("DeliveryStatus") == "Delivered":
            break
        time.sleep(3)

    return {
        "send": send_result,
        "delivery": delivery,
        "otp": send_result["_otp"],
    }

Usage

result = send_otp_and_wait_delivery("+916296346452")
otp = result["otp"]          # store in Redis/DB with expiry
job_id = result["send"]["JobId"]

cURL (quick test)

Send OTP

curl -sS -L -G "https://ultronsms.com/api/mt/SendSMS" \
  --data-urlencode "user=GENZENITH" \
  --data-urlencode "password=dssdl@33" \
  --data-urlencode "senderid=URMIAI" \
  --data-urlencode "channel=Trans" \
  --data-urlencode "DCS=0" \
  --data-urlencode "flashsms=0" \
  --data-urlencode "number=916296346452" \
  --data-urlencode "text=Your URMI app verification code is 482916. It is valid for 10 minutes. Do not share it to anyone - URMI AI" \
  --data-urlencode "route=2" \
  --data-urlencode "peid=1701178780498045011" \
  --data-urlencode "dlttemplateid=1777178797989033323"

Check delivery

curl -sS -L -G "https://ultronsms.com/api/mt/GetDelivery" \
  --data-urlencode "user=GENZENITH" \
  --data-urlencode "password=dssdl@33" \
  --data-urlencode "jobid=211261464"

Application integration checklist

  • Generate OTP server-side; store with TTL matching template validity (10 minutes).
  • Rate-limit OTP requests per phone number and IP.
  • Do not log full OTP or password in application logs.
  • Verify user-submitted OTP against stored value before marking session verified.
  • Handle ErrorCode != 000 with a generic user message ("Unable to send OTP, try again").
  • Use demo account (GENZENITHDemo) only in non-production environments.

Verified test (2026-08-30)

Field Value
Number +91 6296346452
Job ID 211261464
Message ID X4jHLUsSDUSu6cD3yodiYw
Delivery Delivered at 2026-08-30T11:37:18.523