Skip to main content

Get All Packages

Retrieve available eSIM packages with your pricing.

Endpoint​

GET /api/v1/business/esims/packages

AI prompt — Get All Packages

Open raw .txt

Paste into ChatGPT, Claude, Cursor, Copilot or any coding agent to generate this part of your integration. Built-in recommendation: Sync the catalogue into your own database every 6–12 h (limit=100, ~70 paced requests) and serve your storefront from it — never proxy this endpoint.

Show prompt text (70 lines)
# eSIMfly Business API — Get All Packages (GET /esims/packages) — prompt for AI coding assistants

TASK: build a CATALOGUE SYNC that copies the eSIMfly package list into our own database on a
schedule, and serve our storefront from that database. Do NOT call this endpoint per customer
request, per search, or per page view. Do NOT proxy it.

WHY: the endpoint assembles and prices the entire multi-provider catalogue (7,000+ packages) on
every call and paginates in memory. A local copy is faster for customers, keeps us far inside the
rate limits, and is much cheaper for eSIMfly. Prices only change occasionally, and the order
endpoint always charges the current price anyway (you only send packageCode).

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/packages?page=1&limit=100
  Query params: page (default 1), limit (default 50, max 100),
                type = local | regional | global   (optional; enterprise self-service accounts get "enterprise"),
                search = country/region name        (optional; ad-hoc lookups only — NOT for the sync).

RESPONSE 200
  { "success": true, "data": { "packages": [Package, ...],
    "pagination": { "page": 1, "limit": 100, "total": 7123, "total_pages": 72 } } }
  Package = {
    package_code: string (OPAQUE — "PHAJHEAYP", "1654977", "ent_1234567", "merhaba-7days-1gb"),
    name, region, type: "local"|"regional"|"global"|"enterprise",
    data_amount_gb: number, validity_days: int, cost: number (YOUR buy price), currency: "USD"|"IQD"|"EUR",
    features: { voice_minutes, sms_count, is_rechargeable }, is_unlimited, has_voice, has_sms,
    countries?: ["AT","BE",...]            // ISO alpha-2, eSIMfly packages — full coverage list for regional/global
    locationNetworkList: [{ locationName, locationLogo, operatorList: [{ operatorName, networkType }] }],
    networks?: [{ network_id, network_name, network_type, country_code, country_name, country_iso2, continent, mcc_code, mnc_code }],
    // O2 / Vodafone / Bouygues extras (optional): phone_number, network_carrier, has_5g, has_hotspot, can_extend,
    // is_recurring, activation_policy: "immediate"|"first_use", data_breakdown, voice_details
  }
  Notes: only packages >= 1 GB are returned; sorted local -> regional -> global; duplicate unlimited
  plans are collapsed to the cheapest per duration.

SYNC ALGORITHM (implement exactly)
1. Job runs every 6–12 hours (cron) and on demand from an admin "Sync now" button. Use a lock so
   two syncs never overlap.
2. run_started_at = now(). page = 1. Loop:
     GET /esims/packages?page={page}&limit=100  (fresh RT-RequestID each time)
     upsert every package by package_code, set last_seen_at = run_started_at, is_active = true
     sleep 1000 ms; page++ ; stop when page > data.pagination.total_pages
   ~72 requests for ~7,000 packages. On RATE_LIMIT_EXCEEDED wait 60 s and retry the same page (max 3).
3. If EVERY page succeeded: UPDATE packages SET is_active = false WHERE last_seen_at < run_started_at.
   If any page failed: skip this step, keep the previous catalogue live, alert an admin.
4. NEVER DELETE package rows — orders, eSIMs and invoices reference package_code.
5. Store JSON columns for features, countries, locationNetworkList, networks and provider extras.
   Add our own columns: sell_price (cost + margin, recomputed after each sync), is_active,
   last_seen_at, synced_at, and a search index on name/region/countries.
6. Storefront reads (listing, search, country filter, price) hit OUR database only.
7. Keep `cost` as the authoritative buy price; margin lives in our DB. When you show a price,
   use sell_price; when you order, send only package_code (the API charges current cost).

DELIVERABLE: migration for the packages table, the paced sync job (with lock + abort-safe
deactivation), an admin trigger, and repository functions the storefront uses instead of the API.

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 packages by country name or destination
typeString-Filter by package type: "local", "regional", or "global". Enterprise self-service accounts return "enterprise" instead — see Enterprise accounts
pageInteger1Page number for pagination
limitInteger50Number of results per page (max 100)

Response​

Success Response (200 OK)​

USD User Example:

{
"success": true,
"data": {
"packages": [
{
"package_code": "PHAJHEAYP",
"name": "United States 1GB 7Days",
"region": "United States",
"type": "local",
"data_amount_gb": 1,
"validity_days": 7,
"cost": 1.44,
"currency": "USD",
"features": {
"voice_minutes": 0,
"sms_count": 0,
"is_rechargeable": true
},
"is_unlimited": false,
"has_voice": false,
"has_sms": false,
"countries": ["US"],
"locationNetworkList": [
{
"locationName": "United States",
"locationLogo": "/images/flags/us.png",
"operatorList": [
{
"operatorName": "Verizon",
"networkType": "5G"
},
{
"operatorName": "T-Mobile",
"networkType": "5G"
}
]
}
],
"networks": [
{
"network_id": 310,
"network_name": "Verizon",
"network_type": "5G",
"country_code": "us",
"country_name": "United States",
"country_iso2": "us",
"continent": "North America",
"mcc_code": "311",
"mnc_code": "480"
},
{
"network_id": 311,
"network_name": "T-Mobile",
"network_type": "5G",
"country_code": "us",
"country_name": "United States",
"country_iso2": "us",
"continent": "North America",
"mcc_code": "310",
"mnc_code": "260"
}
]
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 245,
"total_pages": 5
}
}
}

IQD User Example:

{
"success": true,
"data": {
"packages": [
{
"package_code": "PHAJHEAYP",
"name": "United States 1GB 7Days",
"region": "United States",
"type": "local",
"data_amount_gb": 1,
"validity_days": 7,
"cost": 1901,
"currency": "IQD",
"features": {
"voice_minutes": 0,
"sms_count": 0,
"is_rechargeable": true
},
"is_unlimited": false,
"has_voice": false,
"has_sms": false,
"locationNetworkList": [
{
"locationName": "United States",
"locationLogo": "/images/flags/us.png",
"operatorList": [
{
"operatorName": "Verizon",
"networkType": "5G"
}
]
}
]
}
],
"pagination": {
"page": 1,
"limit": 50,
"total": 245,
"total_pages": 5
}
}
}

Package Fields​

FieldTypeDescription
package_codeStringUnique package identifier. Treat it as an opaque string — formats vary by provider (for example "PHAJHEAYP", "1654977", or "ent_1234567" for an enterprise account's own package). Pass it back exactly as received
nameStringPackage display name
regionStringRegion or country name
typeStringPackage type: "local", "regional", "global", or "enterprise" for an enterprise self-service account's own packages
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.voice_minutesIntegerVoice minutes included (0 if none)
features.sms_countIntegerSMS messages included (0 if none)
features.is_rechargeableBooleanWhether package can be recharged
is_unlimitedBooleanUnlimited data flag
has_voiceBooleanHas voice minutes included
has_smsBooleanHas SMS included
countriesArrayISO country codes covered by the package, e.g. ["AT","BE","DE"] (eSIMfly packages). Useful for regional/global packages to see exactly which countries are included
locationNetworkListArrayDetailed network coverage by location
networksArrayRaw per-network coverage rows with MCC/MNC and continent detail (eSIMfly packages). See Networks Structure

Additional Fields (O2, Vodafone, Bouygues Telecom Packages)​

These fields are included for packages from O2, Vodafone, and Bouygues Telecom carriers:

FieldTypeDescription
phone_numberObject/nullIncluded phone number (country, prefix)
network_carrierString/nullCarrier name (e.g., "O2", "Vodafone")
has_5gBoolean5G support
has_hotspotBooleanHotspot/tethering support
can_extendBooleanCan be extended after expiry
is_recurringBooleanSupports auto-renewal subscription
activation_policyString"immediate" or "first_use"
data_breakdownObject/nullUK vs roaming data split (uk_data_gb, roaming_data_gb)
voice_detailsObject/nullCall and text details (see below)

Voice Details Structure​

FieldTypeDescription
uk_calls_unlimitedBooleanUnlimited UK calls
uk_texts_unlimitedBooleanUnlimited UK texts
eu_minutesNumber/"unlimited"/nullEU call minutes included
eu_textsNumber/"unlimited"/nullEU texts included
international_minutesNumber/"unlimited"/nullInternational call minutes
international_textsNumber/"unlimited"/nullInternational texts
sms_inbound_onlyBooleanSMS receive only (no outbound)

LocationNetworkList Structure​

FieldTypeDescription
locationNameStringCountry or location name
locationLogoStringFlag image URL
operatorListArrayList of network operators
operatorList[].operatorNameStringNetwork operator name
operatorList[].networkTypeStringNetwork technology (e.g., "4G/5G")

Networks Structure​

The networks array provides the raw, per-network coverage detail for eSIMfly packages. Each entry is one operator in one country, including MCC/MNC codes — useful for low-level network matching or building your own coverage views.

FieldTypeDescription
network_idInteger/nullInternal network identifier
network_nameString/nullOperator name (e.g., "MCI Iran")
network_typeString/nullNetwork technology (e.g., "4G", "5G")
country_codeString/nullLowercase country code (e.g., "ir")
country_nameString/nullCountry name (e.g., "Iran")
country_iso2String/nullISO 3166-1 alpha-2 code (e.g., "ir")
continentString/nullContinent name (e.g., "Asia")
mcc_codeString/nullMobile Country Code (e.g., "432")
mnc_codeString/nullMobile Network Code (e.g., "11")
note

countries and networks are populated for eSIMfly packages. For regional/global packages, countries lists every covered country and networks enumerates each operator per country. Other providers expose coverage via locationNetworkList.

Examples​

Search for United States Packages​

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

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

Search for Regional Packages​

const queryParams = new URLSearchParams({
search: 'Europe',
limit: 50
});

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

Filter by Package Type​

Get all local packages:

const queryParams = new URLSearchParams({
type: 'local',
limit: 50
});

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

Get all regional packages:

const queryParams = new URLSearchParams({
type: 'regional',
limit: 50
});

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

Get all global packages:

const queryParams = new URLSearchParams({
type: 'global',
limit: 50
});

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

Combine Search and Type Filter​

Search for United States packages with local type only:

const queryParams = new URLSearchParams({
search: 'United States',
type: 'local',
limit: 20
});

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

Pricing​

The cost field shows your cost price. Apply your own profit margin when displaying prices to your customers.

Package Types​

Local Packages (type: "local")​

  • Coverage for a single country
  • Most cost-effective for single-destination travel
  • Example: "United States 1GB - 7 Days"

Regional Packages (type: "regional")​

  • Coverage for multiple countries in a region
  • Ideal for multi-country travel
  • Example: "Europe 5GB - 30 Days" (covers 40+ countries)

Global Packages (type: "global")​

  • Worldwide coverage
  • Premium pricing for maximum flexibility
  • Example: "Discover Global 10GB - 30 Days" (covers 170+ countries)

Filtering Best Practices​

  1. For destination search: Use search parameter with country name
  2. For package type filtering: Use type parameter with values "local", "regional", or "global" (enterprise self-service packages return "enterprise")
  3. Combine filters: You can use both search and type together for precise results
  4. Pagination: Use page and limit for large result sets (default 50, max 100)
  5. Sync, don't proxy: copy the catalogue into your own database on a schedule (every 6–12 hours, limit=100, paced at 1 request/second) and serve your storefront from it. The endpoint assembles and prices the full 7,000+ package catalogue on every call, so per-request use is slow for you and expensive for everyone. See the AI prompt above or the AI / LLM Integration guide

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"
}

Duplicate request ID:

{
"success": false,
"error": "Request ID has already been used",
"code": "DUPLICATE_REQUEST"
}

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"
}

Invalid HMAC signature:

{
"success": false,
"error": "Invalid HMAC signature",
"code": "INVALID_SIGNATURE"
}

Incomplete HMAC authentication:

{
"success": false,
"error": "HMAC signature authentication required",
"message": "Missing required headers: RT-Signature, RT-Timestamp, and RT-RequestID are mandatory when using RT-AccessCode",
"code": "HMAC_REQUIRED"
}

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 packages"
}

Notes​

  • Multi-Currency Pricing: 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
  • Packages are sorted: local plans first (sorted by GB, then unlimited by days), followed by regional, then global
  • Only packages with 1GB or more data are returned (small packages under 1GB are filtered out)
  • Duplicate unlimited plans are filtered, showing only the cheapest option per duration
  • The cost field shows your cost price (your profit margin is not exposed)
  • Package availability may change based on provider stock
  • Use the type parameter to filter packages by coverage type (local/regional/global)
  • Combine search and type parameters for more precise filtering
  • Use pagination for large result sets (7000+ packages available)
  • Sync the catalogue into your own database (every 6–12 hours) instead of calling this endpoint per customer request; never delete synced rows, mark them inactive
  • Use locationNetworkList for detailed network coverage information by location
  • For eSIMfly packages, use countries for the full list of covered ISO country codes and networks for raw per-operator detail (MCC/MNC). Both are especially useful for regional and global packages