List All eSIMs
Retrieve all purchased eSIMs for your business account.
Endpoint
GET /api/v1/business/esims
AI prompt — List All eSIMs
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.
Authentication
This endpoint requires HMAC authentication. See Authentication for details.
Request Headers
| Header | Type | Required | Description |
|---|---|---|---|
| RT-AccessCode | String | Yes | Your API access code |
| RT-RequestID | String | Yes | Unique request ID (UUID v4) |
| RT-Timestamp | String | Yes | Request timestamp in milliseconds |
| RT-Signature | String | Yes | HMAC-SHA256 signature |
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| search | String | - | Search by ICCID, package name, or package code |
| status | String | all | Filter by status: "all", "NEW", "ACTIVE", "EXPIRED", "CANCELLED", "DEPLETED", "DELETED" |
| page | Integer | 1 | Page number for pagination |
| limit | Integer | 20 | Number of results per page (max 100) |
| include_base64 | Boolean | false | Include 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
| Field | Type | Description |
|---|---|---|
| id | Integer | Unique eSIM identifier |
| iccid | String | ICCID (SIM card number) |
| package_name | String | Package display name |
| package_code | String | Package identifier (without provider prefix) |
| countries | Array | List of countries covered |
| status | String | Standardized status: NEW, ACTIVE, EXPIRED, CANCELLED, DEPLETED, DELETED |
| data | Object | Data usage information |
| data.total_mb | Integer | Total data in MB (0 for unlimited) |
| data.used_mb | Integer | Data used in MB |
| data.remaining_mb | Integer | Data remaining in MB (0 for unlimited) |
| data.usage_percentage | Number | Usage percentage (0-100) |
| data.is_unlimited | Boolean | Whether plan has unlimited data |
| validity | Object | Validity period information |
| validity.days | Integer | Total validity days |
| validity.activated_at | String | Activation timestamp (ISO 8601) |
| validity.expires_at | String | Expiration timestamp (ISO 8601) |
| validity.is_expired | Boolean | Whether eSIM has expired |
| qr_code | String | QR code URL for installation |
| qr_code_base64 | String | Base64 QR code data (only if include_base64=true) |
| manual_installation | Object | Manual installation information |
| manual_installation.smdp_address | String | SM-DP+ server address |
| manual_installation.activation_code | String | Activation code for manual entry |
| manual_installation.lpa_format | String | Complete LPA format string |
| direct_apple_installation_url | String | Direct Apple installation URL |
| direct_android_installation_url | String | Direct Android installation URL |
| flag_url | String | Country flag URL |
| created_at | String | Purchase timestamp (ISO 8601) |
| is_pending | Boolean | True if the eSIM is still being provisioned (asynchronously provisioned packages) |
| phone_number | String/null | Phone number included with the eSIM (O2, Vodafone, Bouygues Telecom, Orange packages) |
| imsi | String/null | IMSI of the eSIM profile |
| sim_status | String/null | Provider SIM resource status (e.g. AFFECTED = assigned, FREE = released). Not an SM-DP+ status. |
| esim_status | String/null | Human-readable lifecycle label: New, Assigned (Not Installed), Installed, Active, Not Active |
| profile_status | String/null | eSIM profile (BPP) install status (e.g. Enable, Disable) |
Status Values
Standardized Status Mapping
The API returns standardized status values that map various provider statuses:
| Status | Description | Provider Status Examples |
|---|---|---|
| NEW | Not yet activated | new, got_resource, onboard, NOT_ACTIVE (with data) |
| ACTIVE | Currently active | active, in_use |
| EXPIRED | Validity period ended | expired, NOT_ACTIVE (without data) |
| CANCELLED | Cancelled by user/system | canceled, cancelled, cancel |
| DEPLETED | Data fully consumed | depleted |
| DELETED | Permanently deleted | deleted |
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= 0remaining_mb= 0is_unlimited= trueusage_percentageshows 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=trueto 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
- Use status filters to reduce response size when you only need specific eSIMs
- Implement pagination for accounts with many eSIMs
- Cache results appropriately - eSIM data changes when activated or used
- Use search for finding specific eSIMs by ICCID
- Monitor data usage regularly for active eSIMs
- 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_base64field is only included wheninclude_base64=true - All timestamps are in ISO 8601 format (UTC)