Coverage Blog About
Technical Note

eSIM Activation Codes and Install Links: A Developer's Guide

August 30, 2026 7 min read Zesimo Editorial

A QR code went out to a customer, scanned perfectly, and installed nothing. The image was clean and the camera read it first time. What had been encoded was a web address, and the phone was waiting for a line of text starting LPA:1$.

That line is the activation code. A QR image, a tap-to-install link and a manual entry screen are three ways of handing the same line to a phone. Most install problems turn out to be problems with the line. This guide covers what the code contains, what to encode, what to send your customer, and what to say when someone reports that a code has already been used.

activation code one line of text QR code scanned from another screen tap-to-install link tapped on the phone itself manual entry typed into settings the phone's LPA Local Profile Assistant downloads the profile SM-DP+ server holds the profile
Whichever route the code takes, it ends at the same place: the phone's LPA, which then fetches the profile from the SM-DP+ server over the network.

Encode the activation code, never a URL

The activation code is one line of text, and its format is set by GSMA SGP.22, the Remote SIM Provisioning specification behind consumer eSIM. A complete one looks like this.

1 2 3 4 LPA: 1 $ SMDP.EXAMPLE.COM $ 04386-AGYFT-A74Y8-3F815 1 2 3 4 QR wrapper, dropped when the code is typed format version, always 1 SM-DP+ address, the server holding the profile matching ID, which profile is yours
The four parts of an activation code. Only the LPA: prefix is a QR wrapper, shown here in grey. The three parts underlined in red are the code itself, and they are what goes on a manual entry screen.

SM-DP+ is short for Subscription Manager Data Preparation, and the version number is stricter than it looks: SGP.22 says a device "SHALL treat an AC_Format other than '1' as invalid".

Generate the QR image yourself from that string. Two things go wrong otherwise. Some upstream systems put a hosted web page in the field named for the QR, so encoding whatever you were handed gives you an image that scans and installs nothing. That was the failure at the top of this piece, and it is why our own API points integrators at activation_code and marks the older qrcode field deprecated.

Case is the second one. SGP.22 requires the matching ID to use "upper case alphanumeric characters (0-9, A-Z) and the '-' in any combination", a choice the spec says "allows more compact alphanumeric QR code encoding". The alphanumeric mode in ISO/IEC 18004 has no lowercase in its character set, so one lowercase character pushes the encoder into byte mode and gives you a denser image for the same string. Pass the code through untouched: no re-wrapping, no case normalising, no whitespace trimming that might eat a trailing field.

Keep the LPA: prefix on the QR, drop it for manual entry

LPA: is a QR wrapper. The activation code itself starts at the 1$. SGP.22 settles this in two consecutive sentences:

When entered manually, the Activation Code SHALL be used as defined above. When provided in a QR code according to ISO/IEC 18004, the Activation Code SHALL be prefixed with "LPA:".

So encode LPA:1$... in the QR, and display 1$... wherever a customer will type it by hand. On iPhone that screen is Settings, then Cellular, then Add Cellular Plan, then "Enter Details Manually". The prefix tells a scanner what sort of payload follows, in the way mailto: does in a link. LPA is the Local Profile Assistant, which the Android Open Source Project describes as "a bridge between the SM-DP+ ... and the eUICC chip". It runs the download.

Some handsets accept the prefix on the manual screen anyway. Neither Apple nor Google documents that, so do not build on it.

Parse the activation code by field position

The format runs past those three fields, and the optional ones are where parsers break.

#Optional fieldWhat it carries
4SM-DP+ OIDObject identifier from the server's certificate
5Confirmation code required flag1 when the customer must supply a separate code
6CI public key indicatorAdded in SGP.22 v3.0
7Delete notification for device changeOnly when a profile moves to a new device

Field four is the SM-DP+ OID, and it is the one most often described wrongly. Among the third-party explanations we read while checking this, it was called a confirmation code more often than an object identifier. A parser written on that reading will show a customer a certificate identifier and ask them to treat it as a PIN.

SGP.22's own examples show what the optional fields do to the shape:

1$SMDP.EXAMPLE.COM$04386-AGYFT-A74Y8-3F815
1$SMDP.EXAMPLE.COM$04386-AGYFT-A74Y8-3F815$$1
1$SMDP.EXAMPLE.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746$1
1 2 3 4 5 1 SMDP.EXAMPLE.COM 04386-AGYFT-A74Y8-3F815 1 $ $ $ $ AC format always 1 SM-DP+ address matching ID SM-DP+ OID empty here confirmation code flag
Fields are read by position, so an absent one still holds its slot. That is the doubled $ in the second example above.

Split on $, read fields by index, and expect empty strings in the middle. Counting the fields you got instead of indexing them is what breaks on the codes that carry an OID.

Two more rules from the spec will save you trouble. An activation code without a device-change notification is capped at 255 characters. And a device "SHALL ignore a delimiter and any further parameters" beyond the ones SGP.22 defines, so a longer code from a newer server should still work.

Send an install page instead of a platform link

Both platforms take the same shape of link, one hostname apart:

https://esimsetup.apple.com/esim_qrcode_provisioning
  ?carddata=LPA:1$SMDP.EXAMPLE.COM$04386-AGYFT-A74Y8-3F815

https://esimsetup.android.com/esim_qrcode_provisioning
  ?carddata=LPA:1$SMDP.EXAMPLE.COM$04386-AGYFT-A74Y8-3F815

A customer taps that on the phone the eSIM is meant for, and the operating system opens its install flow with the profile already identified. No scanning, no second device, nothing typed.

Two caveats before you copy the format. Neither Apple nor Google publishes it, so treat it as a working convention. And percent-encode the parameter value, which is what we generate for every eSIM we provision and document as ios_tap_link and android_tap_link.

Inside carddata sits the activation code with its LPA: prefix, the QR form of the string. The path is called esim_qrcode_provisioning and the parameter is called carddata, which describes the design accurately enough: the link stands in for a scan.

Everything else about the two links differs.

Apple documents its version. In Set up eSIM on iPhone, Apple says "Your carrier might send you a link instead of a QR code" and puts the requirement at iOS 17.4 or later. The same release added a second useful path: press and hold a QR image inside an email or a web page, then choose Add eSIM, with no second device involved.

Google documents none of it. The AOSP eSIM guide covers QR codes, activation codes and carrier apps. The Pixel help page for setting up an eSIM lists two flows, and a link is not one of them. We found no published URL format, no stated minimum Android version, and no announcement.

The Android link is Google's all the same. The host esimsetup.android.com serves a Digital Asset Links file handing every URL on the domain to com.google.android.gms, which is Google Play services. It resolves to Google infrastructure, and in a desktop browser on 30 August 2026 it answered with a placeholder page titled "eSIM Setup". It is an ordinary Android App Link with a nearly empty page behind it.

Apple's host works differently. On the day we checked, esimsetup.apple.com published no A, AAAA or CNAME record and could not be reached over HTTPS. There is no web server behind Apple's install link. The URL means something to iOS and to nothing else.

17.4 The iOS version where Apple's install link starts working, per Apple's support page. Google has never published a minimum Android version, a URL format, or an announcement.

Which is why a platform link is only safe when you already know the platform, and in an email you do not. An iPhone customer who taps the Android link lands on an empty Google page. An Android customer who taps the Apple link gets a DNS error and reads it as a broken product.

Send one page instead. Put the QR, both platform links and the activation code as selectable text on it, and let the customer's device take the path that works. Say on that page that they need Wi-Fi, because Apple lists a connection as a prerequisite for installing an eSIM, with a narrow exception for eSIM-only models in some countries. A page also survives being forwarded to a laptop. An AI assistant reading an eSIM over MCP returns that same address, as we described in Your eSIM Catalog Is Now Agent-Native.

Tell "already used" apart from "failed"

These arrive as the same complaint and need opposite answers. Before releasing a profile, the SM-DP+ checks that the profile for that matching ID is in "'Released' state, or, in case of a retry due to a previous installation failure, in 'Downloaded' state". It counts download attempts, and terminates the order once the maximum is passed.

An install that failed can usually be retried with the same code. An install that succeeded cannot. "It didn't work, let me scan again" and "it worked and now I want it on my new phone" are two different problems, and resending the code only answers the first.

The short version

  1. Generate the QR from the activation code yourself, character for character.
  2. Keep LPA: on the QR, drop it wherever the code is typed.
  3. Split on $ and read by index, allowing empty fields.
  4. Send a page, not a platform link, and mention Wi-Fi on it.
  5. Separate "already used" from "failed" before you answer the ticket.

If you are building against Zesimo, activation_code, ios_tap_link, android_tap_link and install_url all sit on the eSIM object, and the hosted page at install_url already does everything on that list.

The Zesimo team

Build on the eSIM catalogue.

Zesimo is a B2B eSIM platform: one API for the catalogue, orders, wallet and eSIM lifecycle, and a hosted install page for every eSIM you sell. The application takes under five minutes.

Apply for reseller access