Core concepts
eSIM installation
Deep links, QR codes and in-app install on iOS and Android.
Ordering an eSIM gets you an activationCode: the LPA string a device uses to
download its profile. Installing it is your user's step, on their own device.
Which methods you can offer depends on the platform and its OS version.
Whichever method you lead with, offer manual install alongside it. The other methods can fail on a particular device or OS version. Manual install works on every eSIM-capable device.
| Method | iOS | Android |
|---|---|---|
| Deep link | 17.4 and up | 10 and up |
| Manual install | Always | Always |
| In-app install | Needs Apple's eSIM entitlement | Needs your app's signing certificate hash on the profile (talk to sales) |
Checking the device
Before you offer an eSIM, check that the device can take one:
GET /catalog/devices returns the whole list by brand, if you'd rather show
it. On the CLI that's firsty catalog devices.
Deep link
From iOS 17.4 and Android 10 (API 29), a link opens the system's own eSIM
setup. Put the activationCode in carddata:
On iOS that's Apple's own install sheet, and it needs no entitlement. Below those versions the link doesn't work, so check the OS version before you show it and offer manual install instead.
Manual install
The user has two ways in:
- Scan a QR code. Render the
activationCodeas a QR code on a second screen, since a device cannot scan its own display. - Type it in. On iOS that's Settings → Mobile Service → Add eSIM (Cellular in US English). On Android the path varies by manufacturer.
Typing takes two values, and both are inside the activationCode:
Show them as two separate fields the user can copy. The device's form labels
the matching ID Activation Code, which is easy to confuse with the whole
activationCode string.
In-app install
Your app can also install the eSIM itself, without sending the user to Settings. That needs approval on each platform first: Apple's eSIM entitlement on iOS, and your app's signing certificate hash on our profiles on Android.
iOS
In-app install uses Apple's CTCellularPlanProvisioning API. Apple only allows
it for apps that hold the com.apple.CommCenter.fine-grained entitlement, with
the value public-cellular-plan. To get it:
- Request it on Apple's eSIM access entitlement form, signed in with your Apple Developer account. The form asks for details of the carrier you work with, including that carrier's Apple Team ID.
- Once Apple approves it, add the entitlement to your app's provisioning profile and entitlements file.
Apple gives no processing time, and its advice is to push the request through the carrier's contact at Apple. Plan for a long lead time, and one you don't control.
At runtime, check supportsCellularPlan() before you call addPlan(with:). If
it returns false, fall back to the deep link on iOS 17.4 and
up, or to manual install.
Android
Android's eSIM API (EuiccManager) only installs a profile for an app whose
signing certificate hash is in that profile's access rules. We put those
hashes on the profiles. Talk to sales to send us the SHA-256
of your Play App Signing certificate, plus your upload or debug certificate for
testing.
The same hash does a second job. Once the eSIM is installed, your app has carrier privileges on it. That's enough to set data roaming and the APN from your app, with no extra manifest permissions and without sending the user into Settings. Start from the eSIM's subscription:
Data roaming goes through setDataRoamingEnabled. It accepts carrier
privileges but isn't in the public SDK, hence the reflection:
Add the APN as a row in Telephony.Carriers:
Replace <apn> with the APN we give you; talk to sales for
it. Update and delete go through the same ContentResolver and URI.
Following the install
Subscribe to the eSIM webhooks to follow the install from your backend:
| Event | What it means |
|---|---|
esim.downloaded | The device has the profile. The install is underway. |
esim.installed | The install finished. |
esim.enabled | The profile is enabled on the device. The user has working data. |
esim.faulted | The download or install failed. reason says why. |
A fault is usually not the end of the attempt. The device can retry, and an
esim.installed that follows supersedes it. The exception is
download_order_expired: the download ran out of attempts, and the user needs
a replacement eSIM.
Each one is a status change on the profile, covered with the rest in
eSIM lifecycle.