Skip to main content

List All eSIMs

Retrieve all purchased eSIMs for your business account.

Endpoint​

GET /api/v1/business/esims

AI prompt — List All eSIMs

Open raw .txt

Paste into ChatGPT, Claude, Cursor, Copilot or any coding agent to generate this part of your integration. Built-in recommendation: Your own eSIM table is the source of truth; use this list for support search and an optional paced nightly reconciliation.

Show prompt text (53 lines)
# eSIMfly Business API — List All eSIMs (GET /esims) — prompt for AI coding assistants

TASK: use this endpoint for RECONCILIATION and SUPPORT LOOKUPS only. Our own esims table (filled from
Create Order responses) is the source of truth for which eSIMs we sold and what we show customers.
Do not list eSIMs from eSIMfly on customer page loads.

COMMON RULES (apply to every eSIMfly request)
- Base URL: https://esimfly.net/api/v1/business
- Headers on every call: RT-AccessCode (esf_...), RT-RequestID (fresh UUID v4 per request; reuse -> 400 DUPLICATE_REQUEST),
  RT-Timestamp (ms since epoch; >5 min old -> 401 INVALID_TIMESTAMP),
  RT-Signature = UPPERCASE hex HMAC-SHA256(secretKey, timestamp + requestId + accessCode + rawBody).
  rawBody = "" for GET; for POST/PUT sign the exact body string you send, with Content-Type: application/json.
- Keep access code + secret key server-side in env vars. Never ship them to a browser or mobile app.
- Responses: { success: true, ... } or { success: false, error|message, code }. Branch on `success` and `code`.
- Rate limits are per API key, shown in the business dashboard (typically 100/minute, 1,000/hour, 10,000/day) -> RATE_LIMIT_EXCEEDED. Pace bulk work at <= 1 req/s.
- Read `currency` from responses (USD | IQD | EUR for enterprise). Never hard-code it. IQD amounts are integers.
- Package codes are opaque strings: store and send back verbatim, never parse or prefix them.
- Node.js/TypeScript: use the official SDK instead of raw HTTP — `npm install @esimfly/sdk`
  (https://github.com/eSimfly-Official/esimfly-sdk-nodejs); it implements these rules. Other languages: implement the contract below.
- Full multi-endpoint prompt: https://docs.esimfly.net/llm/esimfly-api-full-prompt.txt

ENDPOINT
  GET https://esimfly.net/api/v1/business/esims?page=1&limit=100&status=ACTIVE&search=<iccid|name|code>&include_base64=false
  Query: page (default 1), limit (default 20, max 100), status = all|NEW|ACTIVE|EXPIRED|CANCELLED|DEPLETED|DELETED,
         search (ICCID, package name or package code), include_base64 (default false — keep it false).

RESPONSE 200
  { success: true, data: { esims: [{
      id, iccid, package_name, package_code, countries: ["Sweden"], status,
      data: { total_mb, used_mb, remaining_mb, usage_percentage, is_unlimited },   // unlimited: total_mb = 0, remaining_mb = 0
      validity: { days, activated_at, expires_at, is_expired },
      qr_code: "https://storage.esimfly.net/qr-codes/....png",
      manual_installation: { smdp_address, activation_code, lpa_format },
      direct_apple_installation_url, direct_android_installation_url, flag_url, created_at,
      is_pending, phone_number, imsi, sim_status, esim_status, profile_status }],
    pagination: { page, limit, total, total_pages } } }
  Status mapping: NEW (not activated), ACTIVE, EXPIRED, CANCELLED, DEPLETED, DELETED.

INTEGRATION PATTERN
1. Populate our esims table from POST /esims/order responses at purchase time. Do not "import" eSIMs
   by listing this endpoint on every dashboard view.
2. Support lookup: GET /esims?search=<iccid>&limit=1 when an agent searches an ICCID we don't recognise.
3. Optional nightly reconciliation (only if we need fleet-wide usage in our DB):
   GET /esims?status=ACTIVE&limit=100, page through, pace 1 req/s, upsert usage + validity + status by iccid.
   For a fleet of 5,000 active eSIMs that is 50 requests/night.
4. For a single customer viewing one eSIM, use GET /esims/usage/query?iccid=... (cached 5–15 min), not this list.
5. Never set include_base64=true in production (huge responses); render QR from lpa_format if needed.
6. Never poll this endpoint to detect activation or expiry; derive that from the nightly job or the
   single-eSIM lookup when the customer opens the eSIM.

DELIVERABLE: listEsims(params) in the shared client, a support ICCID search, and the optional paced
nightly reconciliation job.

Building the whole integration? Use the complete prompt for all endpoints instead of combining the per-endpoint ones.

Authentication​

This endpoint requires HMAC authentication. See Authentication for details.

Request Headers​

HeaderTypeRequiredDescription
RT-AccessCodeStringYesYour API access code
RT-RequestIDStringYesUnique request ID (UUID v4)
RT-TimestampStringYesRequest timestamp in milliseconds
RT-SignatureStringYesHMAC-SHA256 signature

Query Parameters​

ParameterTypeDefaultDescription
searchString-Search by ICCID, package name, or package code
statusStringallFilter by status: "all", "NEW", "ACTIVE", "EXPIRED", "CANCELLED", "DEPLETED", "DELETED"
pageInteger1Page number for pagination
limitInteger20Number of results per page (max 100)
include_base64BooleanfalseInclude base64 QR code data (for backward compatibility)

Response​

Success Response (200 OK)​

{
"success": true,
"data": {
"esims": [
{
"id": 12345,
"iccid": "8910300001234567890",
"package_name": "Sweden 1GB - 7 Days",
"package_code": "sweden-7days-1gb",
"countries": ["Sweden"],
"status": "ACTIVE",
"data": {
"total_mb": 1024,
"used_mb": 256,
"remaining_mb": 768,
"usage_percentage": 25,
"is_unlimited": false
},
"validity": {
"days": 7,
"activated_at": "2024-01-29T10:30:00Z",
"expires_at": "2024-02-05T10:30:00Z",
"is_expired": false
},
"qr_code": "https://storage.esimfly.net/qr-codes/12345-a1b2c3d4.png",
"manual_installation": {
"smdp_address": "rsp-eu.simlessly.com",
"activation_code": "2D7F456148C640359B6A83E0E5AE34D3",
"lpa_format": "LPA:1$rsp-eu.simlessly.com$2D7F456148C640359B6A83E0E5AE34D3"
},
"direct_apple_installation_url": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=...",
"direct_android_installation_url": "https://esimsetup.android.com/esim_qrcode_provisioning?carddata=...",
"flag_url": "/images/flags/se.png",
"created_at": "2024-01-29T10:30:00Z",
"is_pending": false,
"phone_number": null,
"imsi": "260010185757766",
"sim_status": "AFFECTED",
"esim_status": "Active",
"profile_status": "Enable"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 45,
"total_pages": 3
}
}
}

eSIM Fields​

FieldTypeDescription
idIntegerUnique eSIM identifier
iccidStringICCID (SIM card number)
package_nameStringPackage display name
package_codeStringPackage identifier (without provider prefix)
countriesArrayList of countries covered
statusStringStandardized status: NEW, ACTIVE, EXPIRED, CANCELLED, DEPLETED, DELETED
dataObjectData usage information
data.total_mbIntegerTotal data in MB (0 for unlimited)
data.used_mbIntegerData used in MB
data.remaining_mbIntegerData remaining in MB (0 for unlimited)
data.usage_percentageNumberUsage percentage (0-100)
data.is_unlimitedBooleanWhether plan has unlimited data
validityObjectValidity period information
validity.daysIntegerTotal validity days
validity.activated_atStringActivation timestamp (ISO 8601)
validity.expires_atStringExpiration timestamp (ISO 8601)
validity.is_expiredBooleanWhether eSIM has expired
qr_codeStringQR code URL for installation
qr_code_base64StringBase64 QR code data (only if include_base64=true)
manual_installationObjectManual installation information
manual_installation.smdp_addressStringSM-DP+ server address
manual_installation.activation_codeStringActivation code for manual entry
manual_installation.lpa_formatStringComplete LPA format string
direct_apple_installation_urlStringDirect Apple installation URL
direct_android_installation_urlStringDirect Android installation URL
flag_urlStringCountry flag URL
created_atStringPurchase timestamp (ISO 8601)
is_pendingBooleanTrue if the eSIM is still being provisioned (asynchronously provisioned packages)
phone_numberString/nullPhone number included with the eSIM (O2, Vodafone, Bouygues Telecom, Orange packages)
imsiString/nullIMSI of the eSIM profile
sim_statusString/nullProvider SIM resource status (e.g. AFFECTED = assigned, FREE = released). Not an SM-DP+ status.
esim_statusString/nullHuman-readable lifecycle label: New, Assigned (Not Installed), Installed, Active, Not Active
profile_statusString/nulleSIM profile (BPP) install status (e.g. Enable, Disable)

Status Values​

Standardized Status Mapping​

The API returns standardized status values that map various provider statuses:

StatusDescriptionProvider Status Examples
NEWNot yet activatednew, got_resource, onboard, NOT_ACTIVE (with data)
ACTIVECurrently activeactive, in_use
EXPIREDValidity period endedexpired, NOT_ACTIVE (without data)
CANCELLEDCancelled by user/systemcanceled, cancelled, cancel
DEPLETEDData fully consumeddepleted
DELETEDPermanently deleteddeleted

Examples​

Get All eSIMs​

const response = await fetch(
'https://esimfly.net/api/v1/business/esims',
{
headers: generateHMACHeaders() // Your HMAC function
}
);

Filter by Status​

Get only active eSIMs:

const queryParams = new URLSearchParams({
status: 'ACTIVE',
limit: 50
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: generateHMACHeaders()
}
);

Get new (unactivated) eSIMs:

const queryParams = new URLSearchParams({
status: 'NEW',
limit: 50
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: generateHMACHeaders()
}
);

Search by ICCID​

const queryParams = new URLSearchParams({
search: '8910300001234567890',
limit: 10
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: generateHMACHeaders()
}
);

Search by Package Name​

const queryParams = new URLSearchParams({
search: 'Sweden',
limit: 20
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: generateHMACHeaders()
}
);

Include Base64 QR Code​

const queryParams = new URLSearchParams({
status: 'NEW',
include_base64: 'true'
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: generateHMACHeaders()
}
);

// Response will include qr_code_base64 field

Full Example (Node.js)​

const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');

async function getMyESIMs(status = 'all', page = 1) {
const accessCode = 'esf_your_access_code';
const secretKey = 'sk_your_secret_key';

// Generate HMAC headers
const timestamp = Date.now().toString();
const requestId = uuidv4();
const signData = timestamp + requestId + accessCode;
const signature = crypto.createHmac('sha256', secretKey)
.update(signData)
.digest('hex')
.toUpperCase();

// Build query parameters
const queryParams = new URLSearchParams({
status: status,
page: page.toString(),
limit: '50'
});

const response = await fetch(
`https://esimfly.net/api/v1/business/esims?${queryParams}`,
{
headers: {
'RT-AccessCode': accessCode,
'RT-RequestID': requestId,
'RT-Timestamp': timestamp,
'RT-Signature': signature
}
}
);

const data = await response.json();

if (data.success) {
console.log(`Found ${data.data.esims.length} eSIMs`);
console.log(`Total: ${data.data.pagination.total}`);

// Process each eSIM
data.data.esims.forEach(esim => {
console.log(`ICCID: ${esim.iccid}`);
console.log(`Status: ${esim.status}`);
console.log(`Data: ${esim.data.used_mb}MB / ${esim.data.total_mb}MB`);
console.log(`Countries: ${esim.countries.join(', ')}`);
console.log('---');
});
}

return data;
}

// Example usage
getMyESIMs('ACTIVE', 1);

Data Usage Calculation​

The API automatically calculates data usage from various provider formats:

  • total_mb: Total data allowance in MB (0 for unlimited plans)
  • used_mb: Data consumed in MB
  • remaining_mb: Data remaining in MB
  • usage_percentage: Percentage of data used (0-100)

For unlimited plans:

  • total_mb = 0
  • remaining_mb = 0
  • is_unlimited = true
  • usage_percentage shows actual usage

Installation Methods​

The API provides multiple ways to install eSIMs:

1. QR Code Installation​

  • qr_code: QR code image (URL or base64)
  • Most common method - user scans with device camera
  • Works on all eSIM-compatible devices (iPhone, Samsung, Google Pixel, etc.)

2. Direct Apple Installation​

  • direct_apple_installation_url: One-click installation for iOS
  • Opens directly in iOS settings when tapped
  • Simplest method for iPhone users

3. Direct Android Installation​

  • direct_android_installation_url: One-click installation for Android
  • Opens eSIM setup on supported Android devices
  • Works on Samsung, Google Pixel, and other eSIM-compatible Android devices

4. Manual Installation​

  • manual_installation: Contains all details for manual entry
    • smdp_address: Server address
    • activation_code: Activation code
    • lpa_format: Complete LPA string for copy/paste
  • Used when QR scanning or direct install is not available
  • Works on both iOS and Android

Example manual installation data:

{
"manual_installation": {
"smdp_address": "rsp-eu.simlessly.com",
"activation_code": "2D7F456148C640359B6A83E0E5AE34D3",
"lpa_format": "LPA:1..."
}
}

QR Code Handling​

Default Behavior​

  • QR codes are returned as URLs pointing to optimized images
  • URLs are consistent - same QR code always returns same URL
  • Images are cached for fast delivery

Legacy Support​

  • Set include_base64=true to also receive base64 data
  • Not recommended for production use (increases response size)

Example QR code URL format:

https://storage.esimfly.net/qr-codes/12345-a1b2c3d4.png

Error Responses​

400 Bad Request​

Invalid request ID format:

{
"success": false,
"error": "Invalid or missing RT-RequestID header. Must be a valid UUID v4.",
"code": "INVALID_REQUEST_ID"
}

401 Unauthorized​

Missing authentication:

{
"success": false,
"error": "Authentication required",
"message": "Please provide either Bearer token or complete HMAC signature authentication"
}

Invalid API key:

{
"success": false,
"error": "Invalid API key",
"code": "INVALID_API_KEY"
}

403 Forbidden​

Not a business account:

{
"success": false,
"error": "Invalid user or not a business account",
"code": "INVALID_USER"
}

500 Internal Server Error​

{
"success": false,
"error": "Failed to fetch eSIMs"
}

Pagination​

For accounts with many eSIMs, use pagination parameters:

// Get page 2 with 50 items per page
const queryParams = new URLSearchParams({
page: '2',
limit: '50'
});

Pagination info in response:

{
"pagination": {
"page": 2,
"limit": 50,
"total": 245,
"total_pages": 5
}
}

Best Practices​

  1. Use status filters to reduce response size when you only need specific eSIMs
  2. Implement pagination for accounts with many eSIMs
  3. Cache results appropriately - eSIM data changes when activated or used
  4. Use search for finding specific eSIMs by ICCID
  5. Monitor data usage regularly for active eSIMs
  6. Handle all status types - providers may have different status values

Notes​

  • Status values are standardized across all providers
  • Package codes are returned as-is from the packages endpoint
  • Countries array shows all covered destinations
  • Data usage is calculated from provider-specific formats
  • QR codes are optimized and cached for performance
  • The qr_code_base64 field is only included when include_base64=true
  • All timestamps are in ISO 8601 format (UTC)