eSIMs
Working with eSIM products via the API.
eSIMs use dedicated endpoints and have different handling than gift cards:
| Aspect | Gift Cards | eSIMs |
|---|---|---|
| List endpoint | /products | /products/esims |
| Details endpoint | /products/{id} | /products/esims/{id} |
| Purchase endpoint | /invoices | /esims |
| Package values | Numeric | String (e.g., "3GB, 30 Days") |
| Can top up | No | Yes (with esim_id) |
API Endpoints
| Endpoint | Purpose |
|---|---|
GET /products/esims | List eSIM products |
GET /products/esims/{id} | Get product details with packages |
POST /esims | Purchase new eSIM or top-up existing |
GET /esims | List your purchased eSIMs |
GET /esims/{id} | Get specific eSIM details |
Key Concepts
Data Bundles — Unlike gift cards which use numeric values, eSIM packages use string values combining data and duration: "3GB, 30 Days".
ICCID — The unique identifier for each eSIM, returned as id in responses. Required for top-ups.
Coverage — The coverage field on each product lists country codes where the eSIM works.
Bundle Lifecycle
stateDiagram-v2
[*] --> Purchased: Buy bundle
Purchased --> Active: Install or top-up
Active --> Active: Using data
Active --> Expired: Time runs out
Active --> Depleted: Data runs out
Depleted --> [*]
Expired --> [*]
Once a bundle expires or depletes, remaining data or time is lost.
Purchasing an eSIM
sequenceDiagram
participant App
participant API
participant User
App->>API: GET /products/esims/{id}
API-->>App: Product with packages
App->>API: POST /esims
API-->>App: Invoice with order
App->>API: GET /orders/{id}
API-->>App: QR code in barcode_value
App->>User: Display QR code
User->>User: Scan and install
Request Body
Use the /esims endpoint to purchase:
{
"products": [{
"product_id": "bitrefill-esim-europe",
"value": "3GB, 30 Days",
"quantity": 1
}],
"payment_method": "balance",
"auto_pay": true
}Response
The order contains installation details in redemption_info:
{
"redemption_info": {
"barcode_format": "QRCODE",
"barcode_value": "LPA:1$sm.example.com$MATCHING-ID",
"instructions": "Scan this QR code in your device settings to install"
}
}The barcode_value is what users scan to install the eSIM.
Topping Up an eSIM
The difference between a new purchase and a top-up is the esim_id parameter:
| Action | esim_id parameter |
|---|---|
| New eSIM | Not included |
| Top-up existing | Required |
Top-Up Request
Include the esim_id to add data to an existing eSIM:
{
"products": [{
"product_id": "bitrefill-esim-europe",
"value": "5GB, 30 Days",
"esim_id": "4058965632381351147",
"quantity": 1
}],
"payment_method": "balance",
"auto_pay": true
}Bundle Stacking
When you top up, new bundles are added alongside existing ones — they don't replace them. The device typically consumes bundles in order (oldest first).
{
"package_history": [
{ "package_name": "3GB, 30 Days", "status": "active", "remaining_quantity": 500000000 },
{ "package_name": "5GB, 30 Days", "status": "active", "remaining_quantity": 5000000000 }
]
}- You can only top up with bundles from the same eSIM product
- No reinstallation required — new data activates automatically
- Bundles have independent expiration dates
Managing eSIMs
eSIM Object Fields
| Field | Description |
|---|---|
id | ICCID — the unique eSIM identifier |
rsp_url | SM-DP+ server address |
pin | Activation PIN |
barcode_value | QR code data for installation |
product | Product ID |
installed | Whether installed on a device |
created_time | When purchased |
package_history | All data bundles |
Package History
Each entry in package_history represents a data bundle:
| Field | Description |
|---|---|
package_name | Bundle description (e.g., "3GB, 30 Days") |
data_mb | Data in megabytes |
package_duration | Validity in days |
status | Bundle status |
initial_quantity | Original data in bytes |
remaining_quantity | Current remaining data in bytes |
Bundle Statuses
| Status | Meaning |
|---|---|
active | Currently usable |
expired | Time period ended |
revoked | Bundle was cancelled |
Tracking Data Usage
Calculate remaining data from package_history:
- Sum
remaining_quantityacross all bundles withstatus: "active" - Values are in bytes (divide by 1,073,741,824 for GB)
Updated about 2 months ago