eSIM Status
Get the live status of one of your eSIMs — current status, the network it last connected to, device details, activation/usage timestamps, and data usage — pulled directly from the network in real time. The stored record is updated with the fresh values at the same time.
Endpoint
POST /api/v1/business/esims/status
AI prompt — eSIM Status (live)
Paste into ChatGPT, Claude, Cursor, Copilot or any coding agent to generate this part of your integration. Built-in recommendation: Support-console button only (live carrier query), throttled per eSIM — never on page load or in jobs.
Show prompt text (50 lines)
# eSIMfly Business API — eSIM Status, live (POST /esims/status) — prompt for AI coding assistants
TASK: build a SUPPORT / DIAGNOSTIC tool that fetches the LIVE status of one eSIM straight from the
network. This is the most expensive read in the API (it goes to the carrier in real time). It is
on-demand only: never on page load, never in a cron, never for every eSIM.
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
POST https://esimfly.net/api/v1/business/esims/status
Body: { "iccid": "8948010010036785060" } or { "esimId": 15757 } (one of them)
RESPONSE 200
{ success: true, message: "Live eSIM status retrieved", data: {
iccid, status: "NEW"|"ACTIVE"|"EXPIRED"|"DEPLETED", esim_status: "New"|"Not Active"|"Active"|"Installed"|"Assigned (Not Installed)",
smdp_status, profile: "Enabled"|"Disabled"|"Not Installed"|null, unlimited,
last_network: { operator, mcc, mnc, country, country_iso2, connection_type }, // null fields until first connection
device: { model, imei }, // null until installed
activation_date|null, last_usage_date|null, expiry_date|null,
data_usage: { used_gb, total_gb|null (unlimited), unlimited } } }
The stored record on eSIMfly is refreshed with these values at the same time.
ERRORS: 400 MISSING_IDENTIFIER; 403 FORBIDDEN (not your eSIM); 404 ESIM_NOT_FOUND; 502 PROVIDER_ERROR (network unreachable — show "try again", do not auto-retry in a loop).
INTEGRATION PATTERN
1. Expose it as a "Check live status" button in the support/admin console and (optionally) a
customer-facing "Diagnose my connection" action, rate-limited to e.g. 1 call per eSIM per 60 s.
2. Use it to answer: is the profile installed? which network did it last attach to? is it active?
which device? — typical "no data" tickets. Pair with POST /esims/network-events for the event trail.
3. For routine "how much data is left" use GET /esims/usage/query instead (cheaper, cacheable).
4. Persist the returned snapshot on our esims row (last_network, device, activation_date, usage) so the
ticket view can show the last known state without calling again.
5. Never call this for all eSIMs in a batch or from a scheduled job.
DELIVERABLE: getLiveEsimStatus(iccid) in the shared client, a per-eSIM 60 s throttle, and the support
console panel that renders the snapshot.
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 |
| Content-Type | String | Yes | Must be "application/json" |
Request Body
Identify the eSIM by iccid (recommended) or esimId.
| Field | Type | Required | Description |
|---|---|---|---|
| iccid | String | Yes* | The ICCID of the eSIM to query |
| esimId | Integer | Yes* | The eSIM id (from the eSIM list/order response). Used if iccid is not provided. |
* Provide either iccid or esimId.
{
"iccid": "8948010010036785060"
}
Response
Success Response (200 OK)
{
"success": true,
"message": "Live eSIM status retrieved",
"data": {
"iccid": "8948010010036785060",
"status": "ACTIVE",
"esim_status": "Active",
"smdp_status": "AFFECTED",
"profile": "Enabled",
"unlimited": false,
"last_network": {
"operator": "Optus",
"mcc": "505",
"mnc": "2",
"country": "Australia",
"country_iso2": "AU",
"connection_type": "4G - LTE"
},
"device": {
"model": "GTF7P",
"imei": "350000000000000"
},
"activation_date": "2026-06-26T14:34:40.000Z",
"last_usage_date": "2026-06-26T14:35:21.000Z",
"expiry_date": "2026-07-26T14:34:40.000Z",
"data_usage": {
"used_gb": 0,
"total_gb": 1,
"unlimited": false
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
| success | Boolean | Whether the live status was retrieved |
| message | String | Human-readable summary |
| data.iccid | String | The ICCID of the eSIM |
| data.status | String | Lifecycle status (e.g. NEW, ACTIVE, EXPIRED, DEPLETED) |
| data.esim_status | String | Installation/usage state: New, Not Active, Active, Installed, or Assigned (Not Installed) |
| data.smdp_status | String | SM-DP+ profile status |
| data.profile | String/null | eSIM profile installation state: Enabled, Disabled, or Not Installed |
| data.unlimited | Boolean | Whether the plan is unlimited |
| data.last_network | Object | The network the eSIM most recently connected to (null fields if it has not connected yet) |
| data.last_network.operator | String | Network operator name |
| data.last_network.mcc | String | Mobile Country Code |
| data.last_network.mnc | String | Mobile Network Code |
| data.last_network.country | String | Country of the last network |
| data.last_network.country_iso2 | String | ISO 3166-1 alpha-2 country code |
| data.last_network.connection_type | String | Radio access technology (e.g. 4G - LTE, 5G) |
| data.device | Object | The device the eSIM is installed on (null fields if not installed yet) |
| data.device.model | String | Device model |
| data.device.imei | String | Device IMEI |
| data.activation_date | String/null | When the eSIM was first activated (ISO 8601), or null if not activated |
| data.last_usage_date | String/null | Timestamp of the most recent data session (ISO 8601), derived from the network event log |
| data.expiry_date | String/null | When the plan expires (ISO 8601) |
| data.data_usage | Object | Data usage summary |
| data.data_usage.used_gb | Number | Data used, in GB |
| data.data_usage.total_gb | Number/null | Plan allowance in GB (null for unlimited plans) |
| data.data_usage.unlimited | Boolean | Whether the plan is unlimited |
Error Responses
400 Bad Request
Missing identifier:
{ "success": false, "message": "Provide either iccid or esimId", "code": "MISSING_IDENTIFIER" }
403 Forbidden
eSIM does not belong to your account:
{ "success": false, "message": "You do not have permission to access this eSIM", "code": "FORBIDDEN" }
404 Not Found
{ "success": false, "message": "eSIM not found", "code": "ESIM_NOT_FOUND" }
502 Bad Gateway
The network could not be reached:
{ "success": false, "message": "Failed to fetch live status from the provider", "code": "PROVIDER_ERROR" }
Example
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
async function getEsimStatus(iccid) {
const accessCode = 'esf_your_access_code';
const secretKey = 'sk_your_secret_key';
const body = JSON.stringify({ iccid });
const timestamp = Date.now().toString();
const requestId = uuidv4();
const signData = timestamp + requestId + accessCode + body;
const signature = crypto.createHmac('sha256', secretKey)
.update(signData)
.digest('hex')
.toUpperCase();
const response = await fetch('https://esimfly.net/api/v1/business/esims/status', {
method: 'POST',
headers: {
'RT-AccessCode': accessCode,
'RT-RequestID': requestId,
'RT-Timestamp': timestamp,
'RT-Signature': signature,
'Content-Type': 'application/json'
},
body
});
const data = await response.json();
if (data.success) {
const d = data.data;
console.log(`${d.status} on ${d.last_network.operator || 'no network'} — ${d.data_usage.used_gb} GB used`);
} else {
console.error(`Status lookup failed: ${data.message}`);
}
return data;
}
Notes
- Status is fetched live from the network on every call, so it always reflects the current state.
last_network,device, andactivation_dateare populated only once the eSIM has been installed and has connected to a network — they arenullbeforehand.- For unlimited plans,
data_usage.total_gbisnulland validity is governed byexpiry_date.