Firsty BuildersGuidesWhy two-step eSIM provisioning beats single-call APIs
Architecture

Why two-step eSIM provisioning beats single-call APIs

Bundled provisioning APIs feel simpler. They are worse in production. Here is why separating eSIM creation from package ordering matters.

VVVince VissersMay 22, 2026· 8 min read
Architecture

Why two-step eSIM provisioning beats single-call APIs

When you compare eSIM APIs, you'll see two architectural patterns. Bundled: one API call creates the eSIM and attaches a plan in a single operation. Split: one call creates the eSIM, a separate call attaches a package.

Bundled looks simpler. It's worse in production. Here's why.

What the calls look like

Bundled (the Airalo, eSIM Go, eSIM Access pattern):

http
POST /api/esims
{
  "country": "DE",
  "dataAmount": "3GB",
  "duration": 30
}

Response: { iccid, activationCode, planDetails }

Split (Firsty's pattern):

http
POST /api/v3/esims
{}

Response: {
  data: {
    profileReference: "1234567890123456",
    esimReference: "123456000000000001",
    iccid: "89012345678901234567",
    activationCode: "LPA:1$provider.example.com$..."
  }
}

POST /api/v3/profiles/{profileRef}/esims/{esimRef}/packages
{
  "planReference": "C123456XYZDUSR"
}

Response: 200 OK with packageReference

On the surface, bundled wins on simplicity. You're done in one HTTP call instead of two. Why would anyone choose the extra round trip?

Reason 1: Different operations, different failure modes

Try it yourself

Free sandbox. Real Tier-1 carriers. 60 seconds from signup to credentials.

Get started →

eSIM creation and package ordering fail in different ways.

eSIM creation involves the carrier's HLR/HSS (the database that tracks SIMs on a mobile network). Failures here are slow (multi-second timeouts), rare, and require carrier-side intervention to retry.

Package ordering is a lighter operation on the eSIM provider's side. Failures are faster, more common (plan availability, rate limits), and usually self-recoverable.

In bundled APIs, when something fails, you don't know which part broke. Was your customer's SIM created with the wrong plan? With no plan? Not created at all? You have to retry the whole thing, including the slow carrier-side operation. If the SIM was created successfully but plan attachment failed, retry creates a duplicate SIM.

In split, the failure modes are explicit. eSIM creation failed? Retry that. Package ordering failed? Retry just the package ordering against the existing eSIM. You don't burn carrier resources on retries that didn't need to retry that part.

Reason 2: Pre-provisioning patterns

Some real-world flows want to provision SIMs before knowing which plan they'll use.

Travel app at checkout: customer books a hotel in Tokyo. You could:

  • (a) Provision the SIM now with a Japan plan, hope they don't cancel
  • (b) Wait until departure to provision, risking last-minute carrier issues

Split enables option (c): provision the eSIM now with no package attached. Attach the right package 24 hours before departure when the customer confirms their travel dates. The customer's QR code is ready, they're confident their connectivity is set up, but you didn't commit to a plan until you had to.

Reseller inventory model: a corporate travel manager wants 50 eSIMs ready for their team's upcoming trips. With split, you provision the 50 eSIMs now and attach packages as employees confirm destinations.

Bundled APIs can't do this. You must commit to a plan at provisioning time.

Reason 3: Plan changes mid-cycle

What happens when a customer wants to upgrade their data package mid-month?

Split makes this trivial: order a new package on the existing eSIM. The new package becomes active when the old one expires (or immediately, depending on configuration).

Bundled APIs usually treat each "purchase" as a separate SIM operation. Upgrading requires deactivating the old SIM and creating a new one, which means a new QR code, a new installation, and a confused customer.

Reason 4: Package history and lifecycle

Each eSIM in Firsty can have multiple packages over its lifetime. You can list them via

GET /profiles/{ref}/esims/{ref}/packages/history
, which returns every package the eSIM has ever had, including expired and removed ones.

This kind of history tracking only makes sense when packages are separable from the eSIM. In bundled APIs, the eSIM and the package are conceptually one thing, so history is just a list of SIMs.

When bundled is acceptable

Bundled APIs work fine for one-shot consumer flows where the customer chooses a plan, pays, and installs immediately. Most travel eSIM consumer apps use bundled patterns because that's all their flow needs.

Once you're building anything more complex (B2B resellers, corporate fleets, IoT, multi-stop trips), the limitations of bundled become real costs.

The cost of split

To be fair, split has costs:

  • One extra HTTP request per provisioning (mostly negligible: about 100ms)
  • More state to track (profileReference, esimReference, and packageReference)
  • Tutorials are slightly longer (two API calls instead of one)

These are real but small costs. They're paid once during development. The benefits of split accrue every day in production.

How to choose

If you're building:

  • A simple consumer travel app: either pattern works, bundled is slightly simpler
  • A B2B integration: split is significantly better
  • A reseller platform: split is required
  • An IoT fleet system: split is required
  • Anything with bulk operations: split is required

If you have any chance of growing into a more complex flow, start with a split API. Migrating from bundled to split later is painful because every existing SIM in your database uses the bundled data model.

Firsty's stance

We chose split. We think it's the right default for a developer-first eSIM platform. The API has more endpoints, but each endpoint does one thing well.

If you want to see it in action, our first eSIM tutorial walks through the full flow.

ShareLinkedInX
New guides every Tuesday. No marketing nonsense.