Everything an engineering team needs to plan and ship an eSIM integration: the four building blocks every eSIM API shares, how signed authentication works, the sync-vs-webhook provisioning split, what to evaluate before picking a provider, and the pitfalls that only show up in production.
Every eSIM API integration — whichever provider you choose — decomposes into the same four blocks. Scope your build against them:
The packages you can sell, with your wholesale prices. Cache it — but refresh periodically, because carrier rates change. Filter by country to build destination pages.
One authenticated POST turns a package code into a provisioned eSIM, debited from your account balance. The response carries the full install payload: QR code image, Apple one-tap universal link, and the raw LPA string.
Usage queries ("80% used — top up?"), top-up packages and orders, status, suspend/cancel, and network events. This block turns a one-shot storefront into a product with retention.
Signed requests, balance queries, webhook management, and rate limits. Boring until it isn't — most production incidents live here (see pitfalls below).
An eSIM order spends real money from your balance, so serious APIs sign every request instead of trusting a static key header. The eSIMfly scheme is HMAC-SHA256: four headers — access code, unique request ID, millisecond timestamp, and a signature over timestamp + requestId + accessCode + requestBody. Requests older than 5 minutes are rejected, which kills replay attacks.
// With the official SDK (npm install @esimfly/sdk) this entire block is one line:
// const esimfly = new ESIMfly({ accessCode, secretKey });
// Shown in full so you know exactly what gets signed on every request.
const BASE_URL = 'https://esimfly.net';
const ACCESS_CODE = process.env.ESIMFLY_ACCESS_CODE; // esf_...
const SECRET_KEY = process.env.ESIMFLY_SECRET_KEY; // sk_...
function hmacHeaders(requestBody = '') {
const timestamp = Date.now().toString();
const requestId = uuidv4();
// signData = Timestamp + RequestID + AccessCode + RequestBody
const signData = timestamp + requestId + ACCESS_CODE + requestBody;
const signature = crypto
.createHmac('sha256', SECRET_KEY)
.update(signData)
.digest('hex')
.toUpperCase();
return {
'RT-AccessCode': ACCESS_CODE,
'RT-RequestID': requestId,
'RT-Timestamp': timestamp,
'RT-Signature': signature,
'Content-Type': 'application/json'
};
}Credentials come from Business Dashboard → Settings → API Keys. Keep the secret key server-side only — never ship it in a mobile app or browser bundle.
The minimal happy path is two calls — catalog, then order. A prototype that sells a real eSIM and displays its QR code is a one-day build:
// The minimal happy path - two calls from catalog to installed eSIM
import { ESIMfly } from '@esimfly/sdk';
const esimfly = new ESIMfly({
accessCode: process.env.ESIMFLY_ACCESS_CODE,
secretKey: process.env.ESIMFLY_SECRET_KEY,
});
// 1. What can I sell, and at what wholesale price?
const { packages } = await esimfly.packages.list({ search: 'Turkey', type: 'local' });
// 2. Buy one - returns the full installation payload
const order = await esimfly.orders.create({
packageCode: packages[0].package_code,
idempotencyKey: cart.id, // a retry can never charge twice
});
// order: { orderReference, newBalance, esims: [{ iccid, lpaString, qrCodeUrl,
// directAppleInstallUrl, directAndroidInstallUrl, expired_time, ... }] }The important architectural decision is sync vs async provisioning. Most eSIMfly providers provision synchronously — the order response already contains the eSIM. A few packages return pending_details and are ready a few minutes later — the SDK's orders.waitForEsim() polls until then. Design your order flow as "show the eSIM if it's in the response, otherwise show a 'preparing' state and finish when it's ready" and both cases are covered. What does deserve a webhook is everything after the sale: install, activation and low-data events arrive in real time once you subscribe.
For the full working build — catalog UI, ordering, QR delivery — follow the Node.js storefront tutorial (~30 min) and then top-ups, usage tracking & webhooks.
Questions worth asking of any eSIM API vendor before you commit volume — with eSIMfly's answers for transparency:
Not just how many countries, but which local networks per country and whether plans multi-network switch. eSIMfly: 200 countries, 450+ networks.
Every async carrier adds complexity to your checkout. eSIMfly: most packages synchronous; the few async ones are polled with waitForEsim(), and real-time webhooks cover install, status and low-data events after the sale.
You want QR code + Apple universal link + raw LPA string in one response — anything less degrades your install UX. eSIMfly: all three.
Usage query, top-up catalog per ICCID, suspend/cancel, network events. Without usage data you can't build top-up revenue.
Signed requests (HMAC) beat static keys for an API that spends money. eSIMfly: HMAC-SHA256 (handled by the SDK), limits per API key — typically 100 req/minute and 1,000 req/hour — and a 5-minute timestamp window.
If the docs don't include copy-paste examples in your language, integration time doubles. eSIMfly: an official Node.js SDK (@esimfly/sdk), Python and PHP examples, copy-paste prompts for AI coding assistants, plus an interactive playground.
Signed timestamps older than 5 minutes are rejected. A server with a drifting clock produces intermittent 401s that look like random failures. Run NTP; alert on auth-failure rate.
Users delete emails and switch phones. Persist orderReference, ICCID, QR and LPA string on your side so you can re-deliver the eSIM later — re-ordering costs money, re-displaying is free.
Orders debit your prepaid balance and fail cleanly when it's insufficient — which is still a failed customer checkout. Watch the newBalance field on every order and alert well before empty.
Wholesale prices move with carrier rates. A stale cached catalog means selling at yesterday's cost. Cache, but refresh on a schedule and before large campaigns.
Usage-polling every eSIM every minute burns your per-key budget (typically 1,000 req/hour) fast at scale. Query usage when the user opens their eSIM, and subscribe to esim.usage.threshold and esim.status.changed so the API tells you when something changes.
Four building blocks: a package catalog (what you can sell, with wholesale prices), an ordering endpoint (turns a package code into a provisioned eSIM), delivery UX (QR code, one-tap install links, and the raw LPA string), and lifecycle management (usage queries, top-ups, suspend/cancel, webhooks). A minimal storefront needs only the first three and can be built in a day; lifecycle features make it a real product.
A working prototype — authenticate, pull the catalog, create an order, show the QR code — is typically a one-day build (the eSIMfly Node.js tutorial does it in ~30 minutes with the official @esimfly/sdk). Production hardening (webhooks, balance monitoring, re-delivery of stored eSIMs, error handling) usually adds a few days.
Serious eSIM APIs use signed requests rather than a bare API key. eSIMfly uses HMAC-SHA256: each request carries an access code, a unique request ID, a timestamp, and a signature computed over timestamp + request ID + access code + body with your secret key. Requests older than 5 minutes are rejected, which blocks replay attacks.
The purchase itself does not need webhooks: the order response already contains the QR code, and the few packages that provision asynchronously are simply polled until ready. Webhooks matter after the sale — eSIMfly pushes esim.installed, esim.status.changed and esim.usage.threshold (500/200/100/50 MB left) to your server, so you never poll usage across your fleet. Good rule: launch with the synchronous flow, subscribe to webhooks before you scale.
Coverage (countries AND which local networks), wholesale pricing model and top-up support, what share of orders provision synchronously, delivery payload completeness (QR + Apple universal link + raw LPA), auth security, rate limits, usage/lifecycle endpoints, and whether documentation includes runnable examples. Test the sandbox with your real use case before committing volume.
Create an eSIMfly business account, then generate API credentials (access code + secret key) from Business Dashboard → Settings → API Keys. Coverage spans 200 countries across 450+ networks, with rate limits set per API key (typically 100 requests/minute, 1,000/hour). Wholesale tiers depend on volume — contact sales for rates.
Full endpoint reference, Python and PHP examples, and an interactive playground in the documentation — or start from the API overview and get your keys.