Skip to main content

eSIM API for Developers

Siima's eSIM API is two HTTP calls and no API key. One searches live travel data plans; the other turns a plan into a checkout link with the exact total attached. Your user pays us, gets the QR code by email, and you never touch a card number or a SIM profile. It's a narrow API on purpose, and if you need something wider this page will tell you so.

Auth
None
Cost to call
Free
Format
JSON over HTTPS
Who pays
Your user, on siima.online

First, which kind of eSIM API do you need?

Search “eSIM API” and you'll mostly land on wholesale programmes. They're a different product, and picking the wrong one costs weeks.

Wholesale / reseller APISiima's API
You get backAn installable profile (QR / activation code)A checkout link and the final price
Who’s the merchantYou — your Stripe, your refunds, your support inboxSiima
Before your first callBusiness account, often a prepaid balanceNothing
Pricing you seeWholesale cost; you set the marginRetail price and the all-in total
Good forYour own eSIM brand or an app that sells connectivityTravel tools, itinerary apps, bots and agents that want to offer data without becoming a telco reseller

If you're building a white-label eSIM shop, stop here and go talk to a wholesaler. If you're building a trip planner and want a “get mobile data for Japan” button that actually prices the thing correctly, keep reading.

The endpoints

Base URL https://api.siima.online. Everything comes back wrapped in a data key; errors come back as { "error": ... } with a 4xx or 5xx.

MethodPathWhat it does
GET/api/v1/plansSearch the catalogue. Filters below; paginated.
GET/api/v1/plans/:idOne plan by id. 404 if it doesn’t exist.
POST/api/v1/checkout/linksCreate a checkout link for a plan. Returns the URL and the final total.

Searching plans

curl "https://api.siima.online/api/v1/plans?country=JP&coverageType=country&pageSize=50"

The list is paginated inside the envelope, so the plans themselves sit at data.data. One item, trimmed:

{
  "data": {
    "data": [
      {
        "id": "ee48d368-375d-457b-af7b-8f85c4927d21",
        "name": "eSIM, 1GB, 7 Days, Japan, V2",
        "dataBytes": 1000000000,
        "durationDays": 7,
        "priceUsd": 2.89,
        "countries": ["JP"],
        "coverageType": "country",
        "coverageLabel": null
      }
    ],
    "total": 51,
    "page": 1,
    "pageSize": 50
  }
}
country — ISO 3166 alpha-2, uppercase: JP, PT, US. Matches any plan that covers that country, regional ones included.
coverageType — country, regional or global. Pair with country=JP&coverageType=country to drop the multi-country plans.
region — A broad region tag such as Asia or Europe.
minDataGb — Smallest allowance you’ll accept, in GB. Unlimited plans always pass.
durationDays — Exact validity in days. Not a minimum — 10 won’t return a 15-day plan.
page, pageSize — Defaults 1 and 20. pageSize goes up to 6000 if you want the whole catalogue in one go.

For an itinerary across several countries, a regional plan is usually cheaper than buying one per stop, but region names don't follow the atlas. Read the countries array on each plan rather than trusting the label. The multi-country guide has the human version of that warning.

Three fields that trip people up

priceUsd isn’t the total
It’s the plan price before the checkout service fee and card processing. Fine for sorting plans against each other. Don’t show it as “you’ll pay” — create a link and use amountCents for that.
Unlimited is a huge integer
Unlimited plans report dataBytes as 9007199254740991. Treat anything at or above 1e12 as unlimited, and keep it out of any per-GB maths or your “cheapest per GB” sort breaks.
Unlimited has a shape
1 GB a day at full speed, then 512 kbps until the day resets. Say that in your UI. A user who expects uncapped full speed will be annoyed at you, not at us.

Creating a checkout link

curl -X POST https://api.siima.online/api/v1/checkout/links \
  -H "Content-Type: application/json" \
  -d '{ "planId": "ee48d368-375d-457b-af7b-8f85c4927d21", "currency": "eur", "email": "[email protected]" }'

planId is required. currency is usd, eur or gbp and defaults to USD. email is optional and only pre-fills the checkout form — the buyer still has to prove they own it. You get a 201 back:

{
  "data": {
    "url": "https://siima.online/checkout/guest/new?plan=…&currency=eur&ref=…",
    "orderId": null,
    "amountCents": 338,
    "currency": "eur",
    "planName": "eSIM, 1GB, 7 Days, Japan, V2"
  }
}

amountCents is what the card will be charged, fees included, in the currency you asked for. (338 is what that 2.89 plan came to in euros on the day this was written. Prices move with the catalogue, so don't hard-code it.) orderId is null because there is no order yet, and that's the design: nothing is reserved or charged until the buyer opens the link, confirms their email with a 6-digit code, and pays. A link nobody opens costs nobody anything, so it's safe to create one the moment a user clicks buy, even if half of them change their mind.

An unknown or retired plan id gets a 422, a malformed body a 400. Plans do get retired when the upstream catalogue changes, so don't cache ids for weeks — search again before you build a link.

After the link: what you won't get

The integration ends at the URL. You don't receive a webhook when the buyer pays, and you can't look up their order or their eSIM afterwards — that belongs to them, behind their email. The buyer gets the QR code, a one-tap install link and the manual codes by email, usually within a minute, and our install guide takes it from there.

That's a real limitation if you wanted to show “your eSIM is active” inside your own app. It's also why there's no key, no account and no compliance paperwork on your side. Someone else's payment data never passes through your servers.

Limits and where to call it from

RuleDetail
General rate limit100 requests a minute per IP across /api/v1. Standard RateLimit-* headers tell you where you stand.
Checkout links5 a minute per IP. Plenty for a user clicking buy; not enough to pre-generate links for a whole catalogue, which you shouldn’t need.
Browser callsCross-origin requests from your own site are blocked by CORS. Call from a backend, a serverless function or a native app.
LoggingEach checkout link request is logged with its IP and user agent, to spot abuse. It never blocks a legitimate link.

The catalogue resyncs from upstream on a schedule, so caching search results for an hour or so is sensible and will keep you well under the limit. Cache the plan list, not the totals — create the link at the moment the user commits.

REST or MCP?

If the thing calling us is an LLM, skip REST. The same catalogue is exposed as an MCP server at https://api.siima.online/mcp with five tools, and those tools return fee-inclusive prices directly in USD, EUR or GBP, so the model never sees the pre-fee number at all. There's also a list_regions tool that does the which-countries-are-in-this-region lookup for you. The AI agents guide covers it, and if you just want to try it, the Claude and ChatGPT walkthroughs take about two minutes.

REST is the better fit for deterministic code: a booking flow, a price widget, a Slack bot with fixed commands. If you're sending readers rather than API calls, the affiliate programme is probably what you're after. Buying for a company's travellers on a shared bill is what Siima for business does.

Frequently asked questions

Is there a free eSIM API?
Yes. Siima's eSIM API is free and needs no key: GET https://api.siima.online/api/v1/plans searches the live catalogue, and POST https://api.siima.online/api/v1/checkout/links returns a checkout URL and the final total. Your user pays Siima directly, so there's no reseller account, deposit or balance to manage.
Can I provision eSIM profiles directly through the Siima API?
No. The API returns a checkout link rather than a QR code. The buyer verifies their email with a 6-digit code, pays on siima.online, and receives the QR code by email. If you need to issue profiles yourself under your own brand, you want a wholesale reseller API instead.
Is priceUsd in the plans response the price the customer pays?
No. priceUsd is the plan price before the checkout service fee and card processing. The amountCents returned when you create a checkout link is the exact total the buyer will be charged, in the currency you requested. Show that number to users, not priceUsd.
Can I call the Siima eSIM API from the browser?
Not from your own domain. The API only accepts cross-origin browser requests from siima.online, so call it from your backend, a serverless function or a script. Requests with no Origin header — curl, server code, mobile apps — are accepted.

More guides