Home > My Projects > Otro: Second Phone Number
Otro: Second Phone Number
A real second phone number for calls and texts, on one iPhone. No second SIM, no second device.
| Year | 2026 |
| My role | Solo — product, architecture, iOS, backend, admin, brand |
| Links | App Store | Visit the live site |
Overview 
Otro gives you a second, real phone number that lives inside an app. You pick the country you want a number in, subscribe, and start placing calls and sending texts from a line completely separate from your personal one — without a new SIM card or a second phone. Built for people who need a line they can hand out freely: work calls kept apart from personal ones, a temporary number for marketplace sales, or a throwaway line for online accounts. I shipped the entire product solo across four codebases, from first commit to a live App Store listing in 25 days.
Features 
- Reached 5.7K+ downloads from 150K+ App Store impressions within two months of launch, with 5.6% average conversion
- Native VoIP calling over WebRTC with CallKit incoming-call UI driven by VoIP push, so a call rings like a real call even when the app is closed
- Cold-start call routing: a native AppDelegate plugin reports the call to CallKit synchronously on push receipt, before JavaScript is alive, then the JS layer reconciles state once it boots
- Number search and provisioning per country, with reconciliation against the provider and recovery of orphaned numbers
- Two-way SMS with iMessage-style threads, plus multi-line support to hold several numbers and switch the active line
- Credit wallet with a full ledger and idempotent grants on webhook; per-minute and per-message billing computed at hangup as a queued processor, so a dropped webhook cannot lose revenue or double-charge
- Every vendor sits behind a NestJS injection-token port — the telephony provider was migrated from Twilio to Telnyx mid-build without a single change above the service boundary
- Trust and safety: a Claude-based content classifier plus rule-based checks, graduated reversible restrictions, and a default-deny country allowlist
- Admin back-office with a User 360 view, runtime config changeable without redeploy, and an audit log capturing before/after snapshots on every privileged action
- Lint as architecture enforcement: custom rules block DB access in services, double casts, untyped promises and raw style literals
- ~66,000 lines of TypeScript across four codebases — backend 33k, admin 19k, app 13k, site 0.7k
Built With 
React Native, Expo SDK 54, NestJS 11, TypeScript, PostgreSQL 16, Drizzle ORM, Redis 7, Telnyx Voice, WebRTC, CallKit, VoIP Push, RevenueCat, BullMQ, Socket.io, Next.js 16, Astro, Claude API, APNs, Sentry
Screenshots 
Click on a thumbnail to see the full size picture. Warning: large files, may take a while on a 56k modem.