Building a Global eSIM Platform: Why I Chose This Stack Over Traditional SIM Cards
Six months ago, I stared at a pile of plastic SIM cards on my desk and thought: there has to be a better way. Every traveler knows the ritual — land in a new country, find a kiosk, haggle in a language you barely speak, swap tiny plastic chips, and pray the APN settings work. I'd done it dozens of times across 40+ countries, and every time it felt like 2005.
Today, I run iWanteSIM, a global eSIM platform serving travelers across 200+ countries. No plastic. No kiosks. No APN guesswork. Just tap, install, and connect.
This is the story of the technical decisions behind it — why I chose the stack I did, how the API architecture works, what carrier integrations actually look like under the hood, and the mistakes I made along the way.
The Problem With Physical SIMs (From a Developer's Perspective)
Before I wrote a single line of code, I needed to understand what I was actually replacing. Physical SIM cards aren't just inconvenient for travelers — they're a fundamentally broken distribution model.
A traditional SIM card is a physical chip that stores your IMSI (International Mobile Subscriber Identity) and authentication keys. When you buy one at an airport, here's what happens behind the scenes:
- The carrier pre-provisions that SIM with a specific profile
- The SIM gets physically shipped to a retail location
- You buy it, insert it, and your phone authenticates against the carrier's HLR (Home Location Register)
- If everything matches, you get service
The problems with this model are architectural, not just logistical:
Inventory risk: Carriers must predict demand per country, per plan type, and physically stock SIMs. Get it wrong and you have dead inventory.
Activation friction: The average traveler spends 15-45 minutes getting a local SIM working. That's a terrible onboarding experience.
No remote management: Once a physical SIM is provisioned, changing plans or carriers means swapping the chip.
Environmental waste: Billions of plastic SIM cards are produced and discarded annually.
eSIM (embedded SIM) solves all of this at the protocol level. Instead of a physical chip, an eSIM is a secure element soldered directly onto the device's motherboard. It uses the GSMA's Remote SIM Provisioning (RSP) architecture to download carrier profiles over the air.
The key specification is GSMA SGP.22 (for consumer devices), which defines how a device communicates with an SM-DP+ (Subscription Manager Data Preparation) server to securely download and install a profile. This is the protocol I'd be building against.
The Stack Decision: Why Not Just Use an Off-the-Shelf Solution?
When I started researching, I found two paths:
Path A: Use a white-label eSIM reseller platform. Pay a monthly fee, get a pre-built storefront, and resell their inventory. Zero technical work, but zero differentiation and razor-thin margins.
Path B: Build direct carrier integrations. Negotiate wholesale rates, implement the GSMA specs, and own the entire stack.
I chose Path B. Here's why.
White-label platforms abstract away the hard parts — and the margins. When you resell through a middleman, you're competing on price alone. The platform takes 30-50% of every sale, and you have no control over the provisioning flow, the user experience, or the plan configurations.
Building direct meant I could:
Negotiate wholesale rates directly with carriers and MVNOs
Design the activation flow exactly how I wanted (spoiler: I wanted it to be one tap)
Own the customer data and relationship
Build features that white-label platforms don't offer (like multi-country plans and real-time usage tracking)
The trade-off? I'd need to understand telecom protocols that most web developers never touch.
The Architecture: Monolith First, Microservices Later
I'm a pragmatist about architecture. I've seen too many indie projects die because someone tried to build a Kubernetes cluster for 100 users.
My stack:
Backend: Node.js with Express (TypeScript). I know it, it's fast to iterate, and the ecosystem has everything I need.
Database: PostgreSQL. eSIM provisioning is fundamentally transactional — you're dealing with inventory, activations, and payments that must be atomic.
Queue: BullMQ (Redis-backed). Carrier APIs are slow (2-15 second response times are normal). Every activation goes through a job queue.
Frontend: Next.js. SSR for SEO (travel keywords are competitive), but client-side for the interactive parts.
Infrastructure: Vercel for the frontend, a single Hetzner VPS for the backend. Total hosting cost at launch: €35/month.
Here's the high-level flow when a user buys an eSIM:
User → Checkout → Payment (Stripe) → Webhook → Queue → Carrier API → SM-DP+ → QR Code → User's Phone
The critical path is the queue. Carrier APIs are not Stripe — they don't respond in 200ms. Some take 5 seconds. Some timeout. Some return XML (yes, in 2026). The queue decouples the user-facing experience from the carrier integration, so the user gets an instant confirmation while provisioning happens asynchronously.
// Simplified provisioning flow
async function provisionESIM(order: Order): Promise<ESIMProfile> {
const carrier = await getCarrierForRegion(order.country, order.planType);
const inventory = await reserveInventory(carrier.id, order.planId);
const profile = await carrier.api.activateProfile({
iccid: inventory.iccid,
planId: order.planId,
customerRef: order.id,
});
await sendQRCodeToUser(order.userId, profile.qrCode);
await updateInventory(inventory.id, 'activated');
return profile;
}
The reality is messier. Let me show you what actually happens.
Carrier Integrations: The Part Nobody Talks About
This is where I almost quit.
There are roughly three tiers of eSIM carriers you can integrate with:
Tier 1: Modern API-First Carriers
These are the newer players — companies built in the last 5 years that understand REST APIs, JSON, and webhooks. Their APIs look like what you'd expect:
RESTful endpoints with proper authentication (OAuth2 or API keys)
JSON request/response bodies
Webhook callbacks for provisioning status
Sandbox environments for testing
Rate limits that are actually documented
Integrating with these takes about a week. You read the docs, build a client, test in sandbox, and go live.
Tier 2: Legacy Telecom APIs
These are the established carriers that have been around for decades. Their APIs are... different:
SOAP/XML endpoints (yes, still)
Custom authentication schemes involving certificates and IP whitelisting
Response times of 5-15 seconds
Error codes that don't match the documentation
No sandbox — you test in production with test ICCIDs
Integrating with these takes 2-4 weeks and a lot of patience.
Tier 3: Email-and-Spreadsheet "APIs"
Some carriers, especially in smaller markets, don't have APIs at all. The "integration" is:
- You email them a CSV of ICCIDs to activate
- They process it within 24 hours
- They email back a CSV of QR codes
- You manually upload the QR codes to your system
I wish I was joking. For a few countries, this is still the reality. I built an internal tool that parses these CSVs and automates the upload, but it's not real-time and never will be until those carriers modernize.
The API Design: One Interface, Many Backends
The hardest technical challenge was abstracting over these three tiers of carrier quality. I needed a unified interface so the rest of the system didn't care whether a carrier had a REST API or a CSV email workflow.
I settled on an Adapter Pattern with a shared interface:
interface CarrierAdapter {
readonly id: string;
readonly name: string;
readonly supportedCountries: string[];
readonly provisioningType: 'realtime' | 'batch' | 'manual';
getInventory(country: string): Promise<ESIMInventory[]>;
activateProfile(params: ActivateParams): Promise<ActivationResult>;
getProfileStatus(iccid: string): Promise<ProfileStatus>;
deactivateProfile(iccid: string): Promise<void>;
getUsageData(iccid: string): Promise<UsageData>;
}
Each carrier gets its own adapter implementation. The RESTCarrierAdapter handles Tier 1 carriers with standard HTTP calls. The SOAPCarrierAdapter wraps XML requests. The CSVCarrierAdapter queues emails and parses responses.
The key insight: the adapter handles retries, timeouts, and error normalization. If a carrier returns error code ERR_002 (which means "profile already activated" for one carrier and "invalid ICCID" for another), the adapter normalizes it to a standard ProfileAlreadyActivatedError or InvalidICCIDError.
This normalization layer saved me countless hours of debugging. When a provisioning fails, the system logs a standardized error that I can actually act on, regardless of which carrier generated it.
Real-Time Provisioning: The 30-Second Promise
One of the core UX promises of iWanteSIM is that you get connected within 30 seconds of purchase. Here's how that actually works.
The GSMA SGP.22 spec defines a flow called the "ES2+ interface" between the eSIM platform operator (that's me) and the SM-DP+ server (the carrier's provisioning server). The flow looks like this:
-
Download Order: I send a
DownloadOrderrequest to the SM-DP+ with the EID (eSIM identifier) and the profile to install - Profile Generation: The SM-DP+ generates a unique profile bound to that EID
- Matching ID: The SM-DP+ returns a Matching ID and SM-DP+ address
- QR Code: I encode the Matching ID and SM-DP+ address into a QR code
- User Scans: The user scans the QR code, their device contacts the SM-DP+ directly, and downloads the profile
The critical detail: I never touch the actual profile data. The profile is generated by the carrier's SM-DP+ and downloaded directly by the user's device. My platform only handles the orchestration — requesting the profile, receiving the activation token, and delivering it to the user.
This is both a security feature (I can't intercept profile data) and a scaling advantage (I don't need to handle large binary payloads).
What I'd Do Differently
1. Start With Fewer Carriers
I launched with integrations for 8 carriers across 200+ countries. That was too many. Each carrier has its own quirks, and maintaining 8 adapters from day one meant I was spending 60% of my time on carrier-specific bugs instead of building product features.
If I were starting over, I'd launch with 2-3 carriers covering the top 50 destinations and expand from there.
2. Invest in Monitoring Earlier
Carrier APIs fail in ways you don't expect. One carrier's API went down for 6 hours and I didn't notice until a customer emailed. Now I have:
Health checks that ping each carrier's API every 5 minutes
A dashboard showing provisioning success rates per carrier
Automated fallback: if Carrier A fails for a country, the system tries Carrier B
Slack alerts when any carrier's error rate exceeds 5%
3. Build the eSIM Activation Guide Sooner
I underestimated how many users would need help with the activation process. Even though eSIM is "just scan a QR code," different phone models have different menu paths. Samsung puts eSIM settings in Connections → SIM Manager. iPhones put it in Settings → Cellular → Add eSIM. Pixel phones have yet another path.
I eventually built a comprehensive activation guide with screenshots for every major phone model. It reduced support tickets by 40%. I should have built it before launch.
Why eSIM Wins (The Technical Argument)
If you're a developer evaluating whether to build on eSIM vs traditional SIM infrastructure, here's the technical case:
FactorPhysical SIMeSIM
ProvisioningPhysical manufacturing + shippingOver-the-air, instant
Multi-profileOne profile per SIMUp to 8 profiles stored
Remote managementImpossibleFull OTA lifecycle
SecuritySIM cloning possibleHardware-backed secure element
User experienceInsert, configure APNScan QR, done
EnvironmentalPlastic wasteZero physical waste
The GSMA estimates that by 2028, over 60% of smartphones shipped will be eSIM-only. Apple already removed the physical SIM tray from US iPhones. The writing is on the wall.
For developers, this means the addressable market for eSIM services is growing exponentially while the traditional SIM market shrinks. Building on eSIM infrastructure today is like building mobile apps in 2009 — you're early, but the wave is coming.
The Numbers (Because Building in Public Means Sharing Real Data)
Some actual metrics from running iWanteSIM:
200+ countries covered through 8 carrier partnerships
Average provisioning time: 12 seconds (from purchase to QR code delivery)
Activation success rate: 94.7% (the 5.3% failures are mostly unsupported devices or carrier outages)
Support ticket rate: 3.2% of orders (down from 8% after building the activation guide)
Monthly infrastructure cost: ~€120 (Hetzner VPS, Vercel Pro, Redis Cloud, monitoring)
The biggest surprise? Seasonality is real. Summer months (June-August) see 3x the order volume of winter months. I didn't build for this initially and had to scramble when the queue started backing up during the first summer peak.
What's Next
I'm currently working on:
Multi-country plans: One eSIM that works across multiple countries without switching profiles. Technically challenging because it requires coordinating inventory across carriers.
Usage-based pricing: Instead of fixed data buckets, pay for what you actually use. Requires real-time usage data from carriers, which not all of them support.
An API for other developers: If you're building a travel app, you should be able to sell eSIMs through my platform without dealing with carrier integrations yourself.
The Real Lesson
Building an eSIM platform taught me something I didn't expect: the hardest part of any infrastructure product isn't the technology — it's the integrations. Anyone can build a nice checkout flow. The moat is in the carrier relationships, the error handling, the edge cases, and the years of accumulated knowledge about how telecom actually works.
If you're thinking about building something in the telecom space, my advice is: start with the integrations. Don't build a beautiful frontend first. Get one carrier working end-to-end. Then add another. The product will emerge from the constraints.
Have you worked with telecom APIs or eSIM provisioning? I'd love to hear about your experience — especially the horror stories. Drop a comment below or check out what an eSIM actually is if you're new to the space.



Top comments (0)