Key Takeaways
- OTP from Express through an Android SMS gateway is HTTPS JSON from a worker, a hashed Redis challenge, and your SIM — not a packaged Node SDK.
- Keep the six digits out of logs. Store a hash with a short TTL. Compare on submit.
- India traffic still needs DLT-ready templates and a funded +91 SIM. The framework does not buy TRAI compliance.
- Twilio rents a cloud number and bills per message. This path uses your handset, your operator credit, and a devices-plus-volume service fee.
- Free is 300 SMS lifetime on one device. Exhaust it on staff canaries, not load tests.
Express SMS Gateway with Android Device: OTP is a Node pattern: your API issues a short-lived challenge, a worker talks to the Android SMS gateway API, and the phone’s SIM delivers the bubble. Start from the Android SMS gateway API and the OTP use case. Live field names stay in the Developer Center.
You bring the Android and operator credit. We meter devices and send volume. See device and SMS volume pricing.
Six digits on the wire. A hash in Redis. The radio is someone else’s job.
Express hosts the challenge, not the radio
Express is a good place to mint codes because you already have sessions, rate limits, and Redis. It is a bad place to block on GSM. Recipients still see the SIM’s MSISDN — the same number they can reply to if you enable two-way later. How the gateway works.
If the login handler awaits the modem, every Doze hitch becomes a 504. Queue the SMS. Verify the hash.
How to send OTP from Express
- Generate the code on the server. Never let the browser invent it.
- Hash it.
SET otp:{userId} hash EX 300. - Enqueue a worker job with destination, body, and a stable idempotency key.
- Worker
fetchesPOST https://app.sms-gateway.app/api/v1/messageswith Bearer from env. - On form submit, hash the typed digits and compare. Delete the key. Cap guesses.
Pairing the handset is unchanged: setup · downloads.
Hashed Redis keys
Plaintext OTP in Redis is a dump waiting to happen. Store a hash with a pepper from env. TTL shorter than your product copy (“expires in 5 minutes”). Resend should rotate the code and the idempotency key — otherwise a retry will re-deliver the same digits after the user already used them.
import { createHash, randomInt } from 'node:crypto';
const code = String(randomInt(100000, 1000000));
const hash = createHash('sha256').update(code + process.env.OTP_PEPPER).digest('hex');
await redis.set(`otp:${userId}`, hash, 'EX', 300);
await queue.add('otp-sms', { userId, to, challengeId }, { jobId: challengeId });Conceptual only. Send-body field names must match Developer Center.
India (+91) and DLT
The catalog description mentions India because a lot of Express OTP traffic is +91. That is not a city doorway and it is not a TRAI product. You still register headers and templates with DLT, fund a domestic SIM, and keep promotional copy off the OTP device. India SMS gateway notes. Regulator background: TRAI.
Request vs worker vs SIM
| Layer | Owns | Must not |
|---|---|---|
| Express route | Auth, rate limit, hash write | Await GSM |
| BullMQ / worker | HTTPS POST, timeouts, backoff | Log the six digits |
| Control plane | Queue to a paired device | Invent your challenge |
| Android + SIM | Radio, operator DLR | Share a campaign blast |
| Redis | TTL hash | Store plaintext codes |
Twilio contrast
Aggregators rent a number and bill per message. This product is the opposite: your MSISDN, your airtime, a plan that meters devices and platform volume. Twilio vs Android SMS gateway. Twilio’s own send docs (for the contrast, not a recommendation): Twilio SMS.
HTTPS JSON, not an npm SDK
Do not npm-install a fake “Complete Express SDK.” The worker is fetch plus a Bearer key.
curl -X POST "https://app.sms-gateway.app/api/v1/messages" \
-H "Authorization: Bearer $SMS_GATEWAY_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1b0c8a-9d2e-4c77-9f5a-2b6d1e0f4a83" \
-d '{"to":["+14155552671"],"text":"Your verification code is 481920","type":"sms"}'Delivery: delivery reports. Isolate OTP from bulk: multi-device.
What actually duplicates codes
Blind HTTP retries without Idempotency-Key. Two workers claiming the same job. Logging the body then “replaying from logs.” Phone offline while the user hammers Resend. On Free and Developer, sending pauses when you use the plan SMS allowance rather than silently billing aggregator-style overage. Upgrade or request a custom allowance to continue.
Next steps
Wire hash + queue + one staff canary before you touch login. Install the Android app. Spend the 300 lifetime SMS proving the path — not as unmetered volume.
Related product pages
Jump to the live product docs for this topic—not another long-form article.
- OTP and 2FA SMS on AndroidAuthentication flows
- SMS API documentationLive endpoint reference
- device and SMS volume pricingPlans and allowances
- Android SMS gateway product guideDefinition, product, and how to buy





