first commit

This commit is contained in:
debu-2 2026-10-02 11:22:40 +05:30
commit efa5080897
127 changed files with 18610 additions and 0 deletions

310
OTP_SMS_IMPLEMENTATION.md Normal file
View file

@ -0,0 +1,310 @@
# Ultronsms — URMI OTP flow (hardcoded)
Hardcoded integration for sending **URMI app OTP verification SMS** via [Ultronsms](https://ultronsms.com). 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
```json
{
"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
```json
{
"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)
```python
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
```python
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**
```bash
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**
```bash
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` |