Build a working eSIM storefront on the eSIMfly API: authenticate with HMAC-SHA256, pull the wholesale package catalog, create orders from your account balance, and hand your user a scannable QR code — all in plain Node.js with no SDK required.
fetch) and the uuid packageEvery request carries four headers: your access code, a unique request ID (UUID v4), a millisecond timestamp, and an HMAC-SHA256 signature of timestamp + requestId + accessCode + requestBody computed with your secret key. This prevents tampering and replay attacks — requests older than 5 minutes are rejected.
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
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'
};
}The catalog returns every package you can sell with your wholesale price — coverage spans 200 countries and 450+ networks. Cache it and refresh periodically; prices update as carriers change rates.
async function getPackages(country) {
const query = country ? '?country=' + encodeURIComponent(country) : '';
const res = await fetch(BASE_URL + '/api/v1/business/esims/packages' + query, {
headers: hmacHeaders() // GET request: empty body in the signature
});
const data = await res.json();
return data.data.packages;
}
// Example: list Turkey packages with your wholesale prices
const packages = await getPackages('Turkey');
console.log(packages[0]);
// { package_code: 'TR1GB7D', name: 'Turkey 1 GB 7 Days',
// price: 2.72, data_amount: 1, duration: 7, ... }One POST with a package code buys the eSIM from your account balance and returns the complete installation payload — LPA string, QR code image, and one-tap install links. For most providers this is synchronous; a few (like KDDI Japan) return status: "pending_details" and deliver the eSIM via webhook a few minutes later — covered in part two.
async function createOrder(packageCode, quantity = 1) {
const body = JSON.stringify({ packageCode, quantity });
const res = await fetch(BASE_URL + '/api/v1/business/esims/order', {
method: 'POST',
headers: hmacHeaders(body), // body is part of the HMAC signature
body
});
return res.json();
}
const order = await createOrder('TR1GB7D');
console.log(order.orderReference); // order_1692123456_ab7cd
console.log(order.lpaString); // LPA:1$rsp-3104.idemia.io$DOAZJ-...
console.log(order.newBalance); // 47.28 - charged from your balanceYou get three delivery mechanisms per order — show all of them: the QR code for cross-device installs, the Apple universal link for one-tap iOS installation, and the raw LPA string as a manual fallback.
// The order response contains everything your user needs:
//
// order.qrCodeUrl -> base64 PNG, render it directly:
// <img src={order.qrCodeUrl} alt="Scan to install eSIM" />
//
// order.directAppleInstallUrl -> one-tap install on iOS 17.4+
// (universal link, no QR scanning needed)
//
// order.lpaString -> manual entry fallback
// (Settings > Cellular > Add eSIM > Enter manually)
app.get('/my-esim/:orderRef', async (req, res) => {
const esim = await db.getEsimByOrder(req.params.orderRef);
res.render('esim', {
qrCode: esim.qrCodeUrl,
appleUrl: esim.directAppleInstallUrl,
lpa: esim.lpaString
});
});orderReference, ICCID and the install payload so users can re-open their eSIM later.newBalance and alert yourself before it runs dry.The full endpoint reference, Python and PHP examples, and an interactive playground live in the documentation.