eSimfly Logo
TUTORIAL NODE.JS · ~30 MINUTOS

Cómo vender eSIM en tu app con Node.js

Monta una tienda de eSIM funcional sobre la API de eSIMfly: autentícate con HMAC-SHA256, obtén el catálogo de paquetes a precio mayorista, crea pedidos con cargo al saldo de tu cuenta y entrega a tu usuario un código QR listo para escanear. Todo en Node.js puro, sin SDK.

Requisitos previos

  • Una cuenta business de eSIMfly con saldo: solicita acceso a la API aquí
  • Credenciales de la API (código de acceso + clave secreta) desde Business Dashboard → Settings → API Keys
  • Node.js 18+ (fetch integrado) y el paquete uuid

1. Autentícate con HMAC-SHA256

Cada petición lleva cuatro cabeceras: tu código de acceso, un ID de petición único (UUID v4), una marca de tiempo en milisegundos y una firma HMAC-SHA256 de timestamp + requestId + accessCode + requestBody calculada con tu clave secreta. Así se evitan manipulaciones y ataques de repetición: las peticiones con más de 5 minutos de antigüedad se rechazan.

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'
  };
}

2. Consulta el catálogo de paquetes

El catálogo devuelve todos los paquetes que puedes vender con tu precio mayorista; la cobertura abarca 200 países y más de 450 redes. Guárdalo en caché y actualízalo periódicamente: los precios cambian cuando los operadores modifican sus tarifas.

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, ... }

3. Crea un pedido

Un solo POST con el código del paquete compra la eSIM con cargo al saldo de tu cuenta y devuelve todo lo necesario para instalarla: cadena LPA, imagen del código QR y enlaces de instalación con un toque. En la mayoría de los proveedores es síncrono; unos pocos (como KDDI Japón) devuelven status: "pending_details" y entregan la eSIM por webhook unos minutos después, como se explica en la segunda parte.

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 balance

4. Entrega la eSIM a tu usuario

Cada pedido incluye tres mecanismos de entrega, y conviene mostrarlos todos: el código QR para instalar desde otro dispositivo, el enlace universal de Apple para instalar en iOS con un toque y la cadena LPA en bruto como alternativa manual.

// 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
  });
});

5. Pasa a producción

  • Guarda la respuesta del pedido: conserva orderReference, el ICCID y los datos de instalación para que los usuarios puedan volver a abrir su eSIM más tarde.
  • Gestiona los errores de saldo: los pedidos fallan de forma controlada si el saldo es insuficiente; vigila newBalance y avísate antes de que se agote.
  • Respeta los límites: 1000 peticiones por hora y cuenta, y la marca de tiempo de cada petición debe estar dentro de una ventana de 5 minutos (sincroniza los relojes de tus servidores con NTP).
  • Configura webhooks para los proveedores asíncronos: KDDI Japón aprovisiona en segundo plano y entrega la eSIM por webhook; el resto (estado, consumo) se consulta con simples peticiones de sondeo. Continúa con Recargas, control de consumo y webhooks.

¿Listo para empezar a construir?

La referencia completa de endpoints, ejemplos en Python y PHP y un entorno de pruebas interactivo están en la documentación.