eSIM usage
Retrieve the remaining data, voice and SMS balance of one eSIM or of up to 50 eSIMs.
Single eSIM usage
GET /
Permission: Read
The ICCID is 18 to 22 digits (it may be written in groups of spaces or hyphens, 8944 4654 0000 0123 456: the digits
are read) and must belong to an eSIM your agency ordered in this environment. An ICCID
that is unknown, or that belongs to another agency, is answered 404 iccid_not_found.
curl --request GET \
--url 'https://api.fx-port.com/api/v1/esims/usage/8900000540463077957' \
--header 'Authorization: Bearer fxp_test_YOUR_KEY'const iccid = "8900000540463077957";
const response = await fetch(`https://api.fx-port.com/api/v1/esims/usage/${iccid}`, {
headers: { Authorization: "Bearer fxp_test_YOUR_KEY" },
});
const body = await response.json();
const { remaining, total, expired_at, status } = body.data.data; // one level deeper than most answersimport requests
iccid = "8900000540463077957"
response = requests.get(
f"https://api.fx-port.com/api/v1/esims/usage/{iccid}",
headers={"Authorization": "Bearer fxp_test_YOUR_KEY"},
timeout=60,
)
usage = response.json()["data"]["data"]| Query parameter | Description |
|---|---|
force | true skips the 15-minute cache and asks the supplier again. An empty value means not sent |
Response example
{
"environment": "sandbox",
"success": true,
"data": {
"data": {
"remaining": 1024,
"total": 1024,
"expired_at": "2026-11-08 15:23:29",
"is_unlimited": false,
"status": "ACTIVE",
"remaining_voice": 0,
"remaining_text": 0,
"total_voice": 0,
"total_text": 0
},
"meta": { "message": "success" }
}
}An answer that comes from the cache adds two keys at the top level: "cached": true and
"cache_age_seconds": 412 (the age of the answer in seconds). A fresh answer has neither.
Fields of data.data
| Field | Meaning |
|---|---|
remaining, total | Data left and data allowance, in megabytes |
expired_at | When the eSIM expires: YYYY-MM-DD HH:MM:SS in UTC, without a zone |
is_unlimited | true for an unlimited eSIM |
status | The state, as the supplier reports it: ACTIVE (in use), NOT_ACTIVE (not installed or not used yet), FINISHED (the allowance is used up) or EXPIRED (the validity ended) |
remaining_voice, remaining_text, total_voice, total_text | Voice minutes and SMS left and included. 0 for data-only packages |
When the supplier cannot answer
If the supplier is rate limiting or unreachable and FX-Port has a previous answer for this eSIM, you get that
answer, marked as stale, with status 200:
{
"success": true,
"data": { "data": { "remaining": 1024, "total": 1024, "...": "..." }, "meta": { "message": "success" } },
"cached": true,
"stale": true,
"stale_reason": "Rate limited",
"retry_after": 60
}stale_reason says why in a few words and retry_after (seconds, present when the supplier was rate limiting)
says when to ask again. Without a previous answer the call fails instead: 429 rate_limit_exceeded with
retry_after, 503 service_unavailable when the supplier connection is down, or the supplier's own status
with the message "Failed to fetch usage".
In the sandbox, a new eSIM shows its full allowance and the status ACTIVE, and the usage does not change
after a topup.
Bulk usage
GET /
Permission: Read
Returns the usage of several eSIMs in one call, for a list or a dashboard. Always send iccids with the
ICCIDs you show: the supplier is asked one eSIM after another, so a long list that is not cached takes seconds.
curl --request GET \
--url 'https://api.fx-port.com/api/v1/esims/usage/bulk?iccids=8900000540463077957,8900000540463077965' \
--header 'Authorization: Bearer fxp_test_YOUR_KEY'const iccids = ["8900000540463077957", "8900000540463077965"];
const response = await fetch(`https://api.fx-port.com/api/v1/esims/usage/bulk?iccids=${iccids.join(",")}`, {
headers: { Authorization: "Bearer fxp_test_YOUR_KEY" },
});
const { data: entries } = await response.json();
for (const entry of entries) console.log(entry.iccid, entry.status, entry.data?.data.remaining);| Query parameter | Description |
|---|---|
iccids | ICCIDs separated by commas (semicolons and line breaks work too): at most 50 for an API key (400 too_many_iccids above that), each 18 to 22 digits (400 invalid_iccid otherwise). The parameter may also be repeated (iccids=a&iccids=b) or written iccids[]=a&iccids[]=b, and an ICCID may be written in groups of spaces or hyphens. Without it, the 50 newest eSIM orders of your agency in this environment are read |
force | true skips the cache for every eSIM. An empty value means not sent |
- One entry per ICCID, in the order you asked. An eSIM that was topped up still appears once.
- An ICCID that is not an eSIM of your agency is left out of the answer, without an error.
- The same 15-minute cache and stale answers as the single call apply per eSIM.
Response example
{
"environment": "sandbox",
"success": true,
"data": [
{
"iccid": "8900000540463077957",
"data": {
"data": {
"remaining": 1024,
"total": 1024,
"expired_at": "2026-11-08 15:23:29",
"is_unlimited": false,
"status": "ACTIVE",
"remaining_voice": 0,
"remaining_text": 0,
"total_voice": 0,
"total_text": 0
},
"meta": { "message": "success" }
},
"status": "success"
}
]
}Each entry has its own status. Read it per entry: the call answers 200 even when some entries failed.
Entry status | Meaning | data |
|---|---|---|
success | Fresh or cached usage | The usage, one level deeper than the single call: data.data |
stale | The supplier could not answer: the last known usage | The last known usage |
rate_limited | The supplier is rate limiting and there is no previous answer. retry_after says when to ask again | null |
error | The usage could not be read. error is usage_unavailable after an unexpected failure | null |
PENDING | The order has no eSIM yet: its ICCID starts with PENDING- | null |
Retry rate_limited entries later instead of calling bulk usage again at once.
Errors
| HTTP | code | Cause |
|---|---|---|
400 | invalid_iccid | An ICCID is not 18 to 22 digits |
400 | too_many_iccids | More than 50 ICCIDs in iccids (bulk) |
401 | authentication_required, invalid_api_key | Missing or invalid API key |
404 | iccid_not_found | The ICCID is not an eSIM of your agency in this environment (single usage) |
429 | rate_limit_exceeded | Over 6,000 requests per minute for this key, or the supplier is rate limiting and there is no previous answer (retry_after) |
503 | service_unavailable, service_busy | The supplier connection or the service is busy and there is no previous answer. Retry in a few seconds |