telnesstech

Travel eSIM

Integrate Travel eSIM products for international data connectivity

Travel eSIM provides prepaid international data connectivity for travelers. This guide walks you through the Travel eSIM integration, from browsing available packages to provisioning and top-ups.

Core Concept

A Travel eSIM consists of two components:

  • Subscription: The eSIM container that holds the SIM reference (ICC, MSISDN)
  • Data Package (Addon): Contains the actual data allowance, validity period, and supported countries/regions

A subscription always requires at least one data package to be usable. Top-ups are handled by adding additional packages to an existing subscription.

Quick Path

  1. Browse Packages

    List available Travel eSIM data packages filtered by country or region.

  2. Create Order

    Create an order with both the subscription and initial data package.

  3. Calculate Price

    Calculate taxes and totals before payment.

  4. Collect Payment

    Collect payment through your own provider or use a managed payment session.

  5. Submit Order

    Submit the order to provision the eSIM and activate the data package.

Order Structure

When creating a Travel eSIM order, you need two line items:

  1. Subscription line item (TRAVEL_ESIM): Creates the eSIM profile
  2. Addon line item (TRAVEL_ESIM_PACKAGE): Activates the data package
Order
├── Line Item 1: Subscription (TRAVEL_ESIM)
│   └── Gets ICC, MSISDN from provisioning

└── Line Item 2: Addon (TRAVEL_ESIM_PACKAGE)
    ├── dataGb
    ├── validityDays
    ├── countries[] (ISO 3166-1 alpha-2: "ES", "FR")
    ├── regions[] (EUROPE, AMERICAS, ASIA_PACIFIC, GLOBAL)
    └── activationType (INSTANT, FIRST_USE)

Use parentLineItemId to link the addon to a new subscription in the same order. Use subscriptionId when adding packages to an existing subscription.

1. Browse Available Packages

List Travel eSIM data packages available for purchase. You can filter by country or region to show relevant options to your customers.

# List all Travel eSIM addon packages
curl "https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE" \
  -H "X-API-Key: $CONNECT_API_KEY"
// List all Travel eSIM addon packages
const response = await fetch(
  'https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE',
  {
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

const packages = await response.json();
console.log('Available packages:', packages.items);

Filter by Country

# List packages available in Spain
curl "https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE&countries=ES" \
  -H "X-API-Key: $CONNECT_API_KEY"
// List packages available in Spain
const response = await fetch(
  'https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE&countries=ES',
  {
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

Filter by Region

# List packages for Europe
curl "https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE&regions=EUROPE" \
  -H "X-API-Key: $CONNECT_API_KEY"
// List packages for Europe
const response = await fetch(
  'https://apiv2.example.com/api/v2/products/offerings?categories=TRAVEL_ESIM_PACKAGE&regions=EUROPE',
  {
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

Available regions: EUROPE, AMERICAS, ASIA_PACIFIC, GLOBAL

See List Product Offerings

2. Create Order

Create an order with both the subscription (eSIM container) and the initial data package.

curl -X POST "https://apiv2.example.com/api/v2/orders" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "customerId": "123e4567-e89b-12d3-a456-426614174000"
    },
    "lineItems": [
      {
        "type": "SUBSCRIPTION",
        "lineItemId": "esim-container",
        "productOfferingId": "travel-esim-subscription-offering-id",
        "subscriber": {
          "name": "John Doe",
          "email": "john@example.com"
        },
        "sim": {
          "esim": true
        }
      },
      {
        "type": "ADDON",
        "lineItemId": "data-package",
        "productOfferingId": "europe-5gb-30days-offering-id",
        "parentLineItemId": "esim-container"
      }
    ]
  }'
const order = await fetch('https://apiv2.example.com/api/v2/orders', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.CONNECT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    customer: {
      customerId: '123e4567-e89b-12d3-a456-426614174000',
    },
    lineItems: [
      {
        type: 'SUBSCRIPTION',
        lineItemId: 'esim-container',
        productOfferingId: 'travel-esim-subscription-offering-id',
        subscriber: {
          name: 'John Doe',
          email: 'john@example.com',
        },
        sim: {
          esim: true,
        },
      },
      {
        type: 'ADDON',
        lineItemId: 'data-package',
        productOfferingId: 'europe-5gb-30days-offering-id',
        parentLineItemId: 'esim-container',
      },
    ],
  }),
});

const newOrder = await order.json();
console.log('Created order:', newOrder.orderId);

Orders with a TRAVEL_ESIM subscription must include at least one TRAVEL_ESIM_PACKAGE line item. The order will be rejected if no data package is included.

See Create Order

3. Calculate Order Price

Calculate taxes and totals before collecting payment.

curl -X POST "https://apiv2.example.com/api/v2/orders/{orderId}/calculate-price" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json"
const priceCalculation = await fetch(
  `https://apiv2.example.com/api/v2/orders/${newOrder.orderId}/calculate-price`,
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
      'Content-Type': 'application/json',
    },
  },
);

const pricedOrder = await priceCalculation.json();
console.log('Order total:', pricedOrder.pricing.total);

See Calculate Order Price

4. Collect Payment

Travel eSIM orders require prepaid payment before submission. You can collect payment through your own payment provider or use a managed payment session.

Collect payment through your existing payment provider (Stripe, Adyen, Braintree, etc.) and pass the reference when submitting the order. This gives you full control over the checkout experience and lets you use your existing payment infrastructure.

# Step 1: Collect payment through your own provider
# (This happens in your existing payment flow)

# Step 2: Submit the order with the payment reference
curl -X POST "https://apiv2.example.com/api/v2/orders/{orderId}/submit" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "externalPayment": {
      "reference": "pi_3ABC123def456",
      "receiptDescription": "Travel eSIM data package",
      "receiptUrl": "https://yourapp.com/receipts/abc123"
    }
  }'
// Step 1: Collect payment through your own provider
// (This happens in your existing payment flow)

// Step 2: Submit the order with the payment reference
const submitted = await fetch(
  `https://apiv2.example.com/api/v2/orders/${newOrder.orderId}/submit`,
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      externalPayment: {
        reference: 'pi_3ABC123def456',
        receiptDescription: 'Travel eSIM data package',
        receiptUrl: 'https://yourapp.com/receipts/abc123',
      },
    }),
  },
);

When using external payments, you are responsible for collecting the correct amount and handling refunds through your payment provider.

Option B: Payment Session API

If you prefer a managed payment flow, use the Payment Session API to create a payment session. You can use a hosted checkout page or an embedded payment widget.

curl -X POST "https://apiv2.example.com/api/v2/payment-sessions" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "orderId": "{orderId}",
    "paymentProvider": "STRIPE",
    "hosted": true,
    "returnUrl": "https://yourapp.com/payment/success",
    "cancelUrl": "https://yourapp.com/payment/cancel"
  }'

# Redirect customer to provider.checkoutUrl from the response for payment
const paymentSession = await fetch('https://apiv2.example.com/api/v2/payment-sessions', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.CONNECT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    orderId: newOrder.orderId,
    paymentProvider: 'STRIPE',
    hosted: true,
    returnUrl: 'https://yourapp.com/payment/success',
    cancelUrl: 'https://yourapp.com/payment/cancel',
  }),
});

const session = await paymentSession.json();
// Redirect customer to session.provider.checkoutUrl for payment

See Create Payment Session

5. Submit Order

Submit the order to provision the eSIM and activate the data package. If you used external payment (Option A), the order is already submitted from step 4. If you used a payment session (Option B), submit the order with the payment session ID.

curl -X POST "https://apiv2.example.com/api/v2/orders/{orderId}/submit" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentSessionId": "{paymentSessionId}"
  }'

# The created subscription ID is in createdEntities.subscriptions in the response
const submitted = await fetch(
  `https://apiv2.example.com/api/v2/orders/${newOrder.orderId}/submit`,
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      paymentSessionId: session.paymentSessionId,
    }),
  },
);

const submittedOrder = await submitted.json();
console.log('Order state:', submittedOrder.state);

// Get the created subscription
const subscriptionId = submittedOrder.createdEntities.subscriptions[0].subscriptionId;

See Submit Order

6. Retrieve eSIM QR Code

After the order is submitted, retrieve the eSIM QR code for the customer to install on their device.

curl "https://apiv2.example.com/api/v2/subscriptions/{subscriptionId}/esim/qrcode" \
  -H "X-API-Key: $CONNECT_API_KEY"

# Display the returned QR code to the customer for eSIM installation
const qrCode = await fetch(
  `https://apiv2.example.com/api/v2/subscriptions/${subscriptionId}/esim/qrcode`,
  {
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

const qrData = await qrCode.json();
// Display QR code to customer for eSIM installation

See Get eSIM QR Code

Top-Up: Add More Data

When a customer needs more data, create a new order with an addon line item linked to the existing subscription.

curl -X POST "https://apiv2.example.com/api/v2/orders" \
  -H "X-API-Key: $CONNECT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer": {
      "customerId": "123e4567-e89b-12d3-a456-426614174000"
    },
    "lineItems": [
      {
        "type": "ADDON",
        "lineItemId": "topup-package",
        "productOfferingId": "europe-10gb-30days-offering-id",
        "subscriptionId": "{subscriptionId}"
      }
    ]
  }'

# Continue with calculate-price, payment, and submit as above
const topupOrder = await fetch('https://apiv2.example.com/api/v2/orders', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.CONNECT_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    customer: {
      customerId: '123e4567-e89b-12d3-a456-426614174000',
    },
    lineItems: [
      {
        type: 'ADDON',
        lineItemId: 'topup-package',
        productOfferingId: 'europe-10gb-30days-offering-id',
        subscriptionId: subscriptionId, // Link to existing subscription
      },
    ],
  }),
});

// Continue with calculate-price, payment, and submit as above

Multiple data packages can coexist on one subscription, even covering different regions. Each package has its own validity period and data allowance.

Check Usage

Monitor data consumption for a Travel eSIM subscription.

curl "https://apiv2.example.com/api/v2/subscriptions/{subscriptionId}/usage" \
  -H "X-API-Key: $CONNECT_API_KEY"
const usage = await fetch(
  `https://apiv2.example.com/api/v2/subscriptions/${subscriptionId}/usage`,
  {
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

const usageData = await usage.json();
console.log('Data used:', usageData.dataUsed);
console.log('Data remaining:', usageData.dataRemaining);

See Get Subscription Usage

Subscription States

State Description
PENDING Order submitted, awaiting provisioning
ACTIVE eSIM provisioned and ready for use
CANCELLED Subscription terminated

The subscription stays ACTIVE even when data packages expire. Customers can always add more packages to continue using the eSIM.

Data Package States

State Description
PENDING Package ordered, awaiting activation
ACTIVE Package activated and data available
EXPIRED Validity period ended
CANCELLED Package canceled before expiration

Activation Types

Data packages support two activation types:

  • INSTANT: Package activates immediately upon order submission
  • FIRST_USE: Package activates when the customer first connects to the network

Cancel Subscription

To cancel a Travel eSIM subscription:

curl -X POST "https://apiv2.example.com/api/v2/subscriptions/{subscriptionId}/cancel" \
  -H "X-API-Key: $CONNECT_API_KEY"
const cancelled = await fetch(
  `https://apiv2.example.com/api/v2/subscriptions/${subscriptionId}/cancel`,
  {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.CONNECT_API_KEY,
    },
  },
);

See Cancel Subscription

Next Steps