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.
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 API | Siima's API | |
|---|---|---|
| You get back | An installable profile (QR / activation code) | A checkout link and the final price |
| Who’s the merchant | You — your Stripe, your refunds, your support inbox | Siima |
| Before your first call | Business account, often a prepaid balance | Nothing |
| Pricing you see | Wholesale cost; you set the margin | Retail price and the all-in total |
| Good for | Your own eSIM brand or an app that sells connectivity | Travel 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.
| Method | Path | What it does |
|---|---|---|
| GET | /api/v1/plans | Search the catalogue. Filters below; paginated. |
| GET | /api/v1/plans/:id | One plan by id. 404 if it doesn’t exist. |
| POST | /api/v1/checkout/links | Create 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
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=…¤cy=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
| Rule | Detail |
|---|---|
| General rate limit | 100 requests a minute per IP across /api/v1. Standard RateLimit-* headers tell you where you stand. |
| Checkout links | 5 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 calls | Cross-origin requests from your own site are blocked by CORS. Call from a backend, a serverless function or a native app. |
| Logging | Each 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.