The LPA activation code format explained
What the LPA format actually is, how to render QR codes from it correctly, and why some QR codes work on iPhone but not Android.
The LPA activation code format explained
The first time most developers see an eSIM activation code, it looks like garbage:
LPA:1$rsp.example.com$XYZ123ABC
What is this? Why does it have dollar signs? Why does the phone know what to do with it?
This post explains the LPA format, how to render it as a QR code that actually scans, and the surprisingly common bugs that make activation fail silently.
What LPA stands for
LPA means Local Profile Assistant. It's the GSMA specification (SGP.22) for how a phone's eSIM software downloads and installs a profile from a carrier.
Every eSIM in the world that's not pre-installed by the manufacturer arrives via LPA. iPhone, Samsung, Pixel, all of them speak the same protocol. That's why your carrier-issued QR code works regardless of which phone you scan it with.
The format breakdown
Try it yourself
Free sandbox. Real Tier-1 carriers. 60 seconds from signup to credentials.
Get started →The LPA activation code has three required fields separated by dollar signs:
LPA:1$rsp.example.com$ABC123XYZ
-
is the protocol version prefix. Always "LPA:1" in current usage. The "1" indicates version 1 of the LPA protocol.
LPA:1 -
is the SM-DP+ server address. This is the carrier's provisioning server. The phone connects to this address to download the actual eSIM profile.
rsp.example.com -
is the matching ID. This identifies your specific eSIM profile on that server. Think of it like a one-time download code.
ABC123XYZ
Some longer codes include two optional fields:
LPA:1$rsp.example.com$ABC123XYZ$1$CONFIRM_CODE
-
The fourth field is the OID (object identifier). Rarely used in practice.
-
The fifth field is a confirmation code, used for additional verification. Some carriers require this, most don't.
For most integrations, you'll work with the three-field format.
Rendering QR codes correctly
You take the LPA string and encode it as a QR code. The phone's camera scans the QR, the OS recognizes the LPA prefix, and the eSIM installer takes over.
The mistake we see most often: developers try to "prettify" the QR code with logos, colors, or rounded corners. These often break scanning.
javascriptconst QRCode = require('qrcode'); await QRCode.toFile('sim.png', activationCode, { width: 400, margin: 2, color: { dark: '#000000', light: '#FFFFFF', } });
Three things matter for QR scanning reliability:
- High contrast: black on white is most reliable. Lime on dark eggplant looks great on your marketing site but scans inconsistently on older phones.
- Adequate size: minimum 200x200 pixels for display, 400x400 if printing. Phone cameras need enough pixels to resolve the QR data.
- Quiet zone (margin): 2-4 modules of white space around the QR. Without this margin, the scanner can't isolate the QR from surrounding content.
If you must add branding, do it outside the QR's bounding box, not inside.
Why some QR codes work on iPhone but not Android
A subtle bug we see: a customer reports their QR code works fine when they scan it with an iPhone, but Android phones say "no eSIM profile found."
Usually the cause is the QR code itself, not the eSIM. Specifically:
- The QR was rendered too small (under 200px)
- The QR was rendered with (low). Use 'M' or 'Q'.
errorCorrectionLevel: 'L' - The QR was screenshotted, then re-screenshotted, losing fidelity each time
iPhone cameras have aggressive correction for marginal QR codes. Android cameras are stricter. If your QR works on iPhone but fails on Android, it's not an eSIM problem, it's a QR rendering problem.
Test on both before shipping.
The manual entry fallback
Some users can't scan QR codes (older devices, accessibility settings, etc.). The LPA format supports manual entry: the user types the SM-DP+ address and matching ID into the phone's settings.
If you're building a consumer-facing flow, always offer manual entry as a fallback. Display the SM-DP+ address and matching ID as copyable strings next to the QR code.
iPhone: Settings, Cellular, Add eSIM, Enter Details Manually. Android: varies by manufacturer, but usually under Network, Mobile network, Add carrier.
Server-side vs client-side QR rendering
Always generate QR codes server-side. Always.
Client-side QR generation (using a JS library in the browser) has three problems:
- The activation code passes through the user's browser, which can leak in browser history, screenshots, or extensions
- Library size: client-side QR libraries are typically 50KB+, hurting page load
- Rendering inconsistency across browsers and devices
The correct pattern: your backend generates the QR PNG, stores it temporarily (5 minute TTL), and returns a URL to the client.
javascriptconst qrBuffer = await QRCode.toBuffer(activationCode, { width: 400 }); const qrUrl = await uploadToCDN(qrBuffer, { ttl: 300 }); return { qrUrl, activationCode };
The client displays the QR via an image tag. The temporary URL expires after the user has installed the eSIM.
What activation codes are NOT
A few common misconceptions worth clearing up:
- Activation codes are not the same as ICCIDs. The ICCID is the SIM's serial number. The activation code is the LPA string for downloading it.
- Activation codes are not reusable. Once a profile is downloaded, the matching ID is consumed. Some carriers allow re-issuing if installation fails; Firsty does.
- Activation codes are not encrypted. They're a one-time secret in plaintext. Treat them like temporary passwords.
Try it yourself
If you've integrated the Firsty API, you've seen LPA codes. If you haven't, our free sandbox gives you one in 60 seconds, and the first eSIM tutorial walks through QR generation.
Related guides
How to provision your first eSIM via API in 30 minutes
From OAuth token to first eSIM activated, with QR code generation server-side. Real code, real credentials, real eSIM, in about 30 minutes.
OAuth2 client credentials in production: what most tutorials get wrong
Token caching, refresh strategy, and the security mistakes we see in production integrations every week.
profileReference vs esimReference vs ICCID: which identifier when?
Three identifiers, three meanings, frequently confused. Here is which one to use where.