Skip to main content

Get Topup Packages

Retrieve available top-up packages for a specific eSIM with your pricing.

Endpoint​

GET /api/v1/business/topup/packages

AI prompt — Get Topup Packages

Open raw .txt

Paste into ChatGPT, Claude, Cursor, Copilot or any coding agent to generate this part of your integration. Built-in recommendation: Call only when the customer opens the top-up screen; cache per ICCID for 10 minutes; never pre-fetch for all eSIMs.

Show prompt text (46 lines)
# eSIMfly Business API — Get Topup Packages (GET /topup/packages) — prompt for AI coding assistants

TASK: fetch the top-up options for ONE eSIM when the customer opens the top-up screen. Top-up
packages are eSIM-specific (they depend on the eSIM's provider and location), so they cannot be
synced in bulk like the main catalogue — but they must not be pre-fetched for every eSIM either.

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/topup/packages?iccid=<iccid>&page=1&limit=100
  Query: iccid (REQUIRED), page (default 1), limit (default 50, max 100).

RESPONSE 200
  { "success": true, "data": { "packages": [
      { "package_code": "TOPUP_PXOO225PI", "name": "Iraq 3GB 30Days", "data_amount_gb": 3, "validity_days": 30,
        "cost": 10.56, "currency": "USD", "features": { "is_rechargeable": true }, "is_unlimited": false } ],
    "pagination": { "page": 1, "limit": 100, "total": 8, "total_pages": 1 } } }
  package_code here is what you pass to POST /topup/order. cost = your buy price.

ERRORS
  400 MISSING_ICCID; 400 ESIM_NOT_TOPPABLE ("Current status: EXPIRED" — only ACTIVE, DEPLETED, USED_EXPIRED,
  or NEW for eSIMfly-provided eSIMs can be topped up); 403 ESIM_ACCESS_DENIED (not your eSIM); 500.

INTEGRATION PATTERN
1. Call ONLY when a customer (or support agent) opens the top-up screen for a specific eSIM.
2. Cache the result per ICCID for ~10 minutes (memory/Redis) so refreshes and back-navigation don't re-call.
3. Never iterate over all eSIMs to pre-load top-up options, and never put this in a cron.
4. Apply our margin to cost for display; pass the exact package_code to POST /topup/order.
5. Treat ESIM_NOT_TOPPABLE as a normal UI state ("this eSIM can't be topped up"), not as an exception.
6. One page with limit=100 is enough in practice; only paginate if total_pages > 1.

DELIVERABLE: getTopupPackages(iccid) with a 10-minute per-ICCID cache, and the top-up screen data loader.

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​

ParameterTypeRequiredDescription
iccidStringYeseSIM ICCID to get compatible topup packages
pageIntegerNoPage number for pagination (default: 1)
limitIntegerNoNumber of results per page (default: 50, max: 100)

Response​

Success Response (200 OK)​

USD User Example:

{
"success": true,
"data": {
"packages": [
{
"package_code": "TOPUP_PXOO225PI",
"name": "Iraq 3GB 30Days",
"data_amount_gb": 3,
"validity_days": 30,
"cost": 10.56,
"currency": "USD",
"features": {
"is_rechargeable": true
},
"is_unlimited": false
},
{
"package_code": "turkey-7days-1gb-topup",
"name": "Turkey 1GB 7Days",
"data_amount_gb": 1,
"validity_days": 7,
"cost": 2.45,
"currency": "USD",
"features": {
"is_rechargeable": true
},
"is_unlimited": false
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 8,
"total_pages": 1
}
}
}

IQD User Example:

{
"success": true,
"data": {
"packages": [
{
"package_code": "TOPUP_PXOO225PI",
"name": "Iraq 3GB 30Days",
"data_amount_gb": 3,
"validity_days": 30,
"cost": 13939,
"currency": "IQD",
"features": {
"is_rechargeable": true
},
"is_unlimited": false
},
{
"package_code": "turkey-7days-1gb-topup",
"name": "Turkey 1GB 7Days",
"data_amount_gb": 1,
"validity_days": 7,
"cost": 3234,
"currency": "IQD",
"features": {
"is_rechargeable": true
},
"is_unlimited": false
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 8,
"total_pages": 1
}
}
}

Package Fields​

FieldTypeDescription
package_codeStringTopup package identifier (use this for topup operations)
nameStringPackage display name
data_amount_gbNumberData allowance in GB
validity_daysIntegerValidity period in days
costNumberYour cost price in user's preferred currency
currencyStringCurrency code based on the account: USD or IQD, or EUR for an enterprise account
featuresObjectPackage features object
features.is_rechargeableBooleanAlways true for topup packages
is_unlimitedBooleanUnlimited data flag

Examples​

Get Topup Packages for Specific eSIM​

const queryParams = new URLSearchParams({
iccid: '8943108170003135816',
limit: 20
});

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

const data = await response.json();
console.log(`Found ${data.data.packages.length} topup packages`);

With Pagination​

const queryParams = new URLSearchParams({
iccid: '8943108170003135816',
page: 1,
limit: 10
});

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

Error Responses​

400 Bad Request​

Missing ICCID parameter:

{
"success": false,
"error": "ICCID parameter is required",
"message": "Topup packages are specific to an eSIM. Please provide the ICCID parameter.",
"code": "MISSING_ICCID"
}

400 Bad Request​

eSIM cannot be topped up due to status:

{
"success": false,
"error": "eSIM cannot be topped up. Current status: EXPIRED",
"message": "Only ACTIVE, DEPLETED, or USED_EXPIRED eSIMs can be topped up (NEW is also allowed for esimfly eSIMs)",
"code": "ESIM_NOT_TOPPABLE"
}

Status comparison is case-insensitive (ACTIVE, Active, and active are all accepted). eSIMs in NEW status can also be topped up when the eSIM is provided by eSIMfly.

403 Forbidden​

eSIM not found or access denied:

{
"success": false,
"error": "eSIM not found or access denied",
"code": "ESIM_ACCESS_DENIED"
}

401 Unauthorized​

See Packages endpoint for common authentication errors.

500 Internal Server Error​

{
"success": false,
"error": "Failed to fetch top-up packages"
}

Important Notes​

Multi-Currency Pricing​

  • Pricing Display: Topup prices are shown in your account currency (USD, IQD, or EUR for enterprise accounts)
  • Currency Conversion: IQD prices are converted using real-time exchange rates
  • Currency Preference: Set your preferred currency in the business dashboard settings
  • Format: USD prices show 2 decimals, IQD prices are whole numbers

Provider-Agnostic Response​

  • Package codes are cleaned and standardized
  • Different package code formats are used depending on the provider
  • All provider-specific handling is done automatically

Package Availability​

  • Topup packages are eSIM-specific - each eSIM has different available options
  • Packages are automatically filtered by the eSIM's location
  • Only compatible topup packages for that specific eSIM are returned

Security​

  • Users can only access topup packages for eSIMs they own
  • ICCID ownership is verified for each request
  • All requests are logged and monitored

Integration Tips​

  1. Always specify ICCID: This endpoint requires the specific eSIM identifier
  2. Use returned package_code: Use the exact package_code from response for topup operations
  3. Automatic handling: The API handles all backend complexity automatically
  4. Pagination: Use pagination for eSIMs with many topup options
  5. Error handling: Always handle the case where no topup packages are available

Relationship to Other Endpoints​

  • Use with Get eSIMs to get ICCIDs
  • Use package_code from this endpoint with topup operations
  • Pricing matches your account's profit margin settings