SimFuse eSIM Storefront
Server Details
SimFuse is a travel eSIM storefront covering 200+ countries and regions. This connector lets an AI assistant plan a trip, compare live prices and open a checkout for eSIM data. Browsing needs no authentication.
What it does:
plan-trip: give the stops (country code and days in each) and it compares one plan covering the whole route against one plan per country against a mix, on live prices, then flags the cheapest complete option and lists any country it cannot cover.
list-destinations: search every country and region SimFuse sells for, with the cheapest plan price per destination.
list-plans and get-plan: browse a destination's plan ladder, filter by data amount, validity and price, and inspect a single plan in detail.
get-plan-coverage: check every country a plan works in before buying.
create-checkout-session: open a checkout for the selected plans at frozen prices. Nothing is charged by that call; payment, completion and cancellation happen over the agentic HTTP API with the returned key.
Good to know: prices come back in minor units of the currency you ask for, data allowances are in megabytes, and quotes are offers rather than reservations, so the charged total is computed at checkout.
Operated by Qorinx OÜ. Buy directly at https://simfuse.app, agent documentation at https://simfuse.app/agent/.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP
- URL
TDQS
Scored across 6 tools
The read-side tools are largely distinct (destinations vs. plans vs. single-plan detail vs. coverage), and descriptions explicitly route between them (e.g., 'ask get-plan instead for data allowance', 'use plan-trip instead for multi-country trips'). The only soft overlaps are list-plans vs. plan-trip for a single country and get-plan vs. get-plan-coverage, but each is called out and defused in the text.
All names are kebab-case verb_noun(s) with predictable action prefixes: list-destinations, list-plans, get-plan, get-plan-coverage, plan-trip, create-checkout-session. No mixing of casing or verb styles; the pattern is easy to infer.
Six tools is well-scoped for a storefront: five read-only discovery/decision tools plus one write tool. Each earns its place with no redundant or filler operations.
Discovery and decision-making are thorough (destinations, plans, plan details, coverage, trip optimization), but the purchase lifecycle is only half-present: create-checkout-session opens a session, yet payment, completion, cancellation, and order/session status are explicitly pushed to an external HTTP API rather than exposed as tools. This leaves agents without a way to finish or check a purchase through the MCP surface.
Available Tools
6 toolscreate-checkout-sessionCreate checkout sessionAInspect
Open a checkout session for one or more eSIM plans at frozen prices, using the plan ids that plan-trip, list-plans or get-plan returned. Use it once the traveller has chosen what to buy. It CHARGES NOTHING and reserves no stock: it prices the basket, freezes those prices until the session's price_locked_until, and hands back the session plus a bearer agent key. Payment, completion and cancellation happen afterwards over the SimFuse agentic HTTP API with that key, as the session's note explains, and the eSIM is delivered by email once payment settles. Each call opens a NEW session and mints a NEW key, so call it once per basket rather than retrying it to re-read one.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | What to buy: one entry per plan, 1 to 50 entries. Pass the whole basket in one call, e.g. [{"id":"01JVQ...","quantity":1}]. | |
| currency | No | Optional. ISO 4217 three-letter code to price the session in, e.g. "USD", "EUR", "GBP". Defaults to EUR. Every amount in the answer is minor units (cents) of this currency. | |
| agent_name | No | Optional. Name of the assistant or app opening the session, e.g. "Claude". Recorded on the agent key so we can tell integrations apart. Defaults to "mcp-client". | |
| buyer_email | No | Optional but strongly recommended. The traveller's email address, where the eSIM and its installation details are sent once payment settles. Ask for it rather than inventing one. |
Output Schema
| Name | Required | Description |
|---|---|---|
| api | Yes | The HTTP endpoints for this session, all taking the agent_key as a bearer token. |
| note | Yes | How to use the key and how long the prices hold. Worth following literally. |
| session | Yes | The priced checkout session, in the same shape the agentic HTTP API returns it. |
| agent_key | Yes | The bearer key for every follow-up call on this session, shown ONCE and never again. Send it as "Authorization: Bearer <key>". It is a credential: use it, do not read it out to the traveller. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag non-read-only and non-idempotent, and the description adds substantial context beyond them: nothing is charged, no stock reserved, prices frozen until price_locked_until, a bearer agent key is minted, delivery is by email after payment settles, and critically that each call creates a NEW session and NEW key so it must not be retried to re-read one.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph, but front-loaded with the action and the critical 'charges nothing / reserves no stock' assurances before the downstream workflow. Nearly every sentence carries information, though a slightly tighter form would read better.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description correctly previews the return (session plus bearer key) and the post-call workflow, and covers the non-idempotent, no-charge semantics an agent needs to avoid duplicate sessions. Nothing material is missing for a 4-param, 1-required mutation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents items, currency, agent_name and buyer_email with ranges and defaults. The description's contribution is limited to the provenance of plan ids, which the schema also states; the baseline 3 applies when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (open a checkout session for eSIM plans) plus the key scope (frozen prices). It is clearly distinguishable from the sibling discovery tools (plan-trip, list-plans, get-plan), which it names as the source of its ids rather than as competitors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('use it once the traveller has chosen what to buy') and explicit exclusions ('CHARGES NOTHING and reserves no stock'), plus a routing note that completion happens afterwards over the agentic HTTP API with the returned key. It also states up front that ids must come from plan-trip, list-plans or get-plan.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-planGet eSIM plan detailsARead-onlyIdempotentInspect
Read everything about one eSIM plan by its id: data allowance, how long it stays valid, what happens after a fair-use cap, whether hotspot and top-ups are supported, the network it runs on, and the retail price in the currency you ask for. Use it to answer a specific question about a plan already found with list-plans or plan-trip, and before buying, to confirm the plan really matches what the traveller asked for. Ask get-plan-coverage instead when the question is which countries it works in. Read-only: it reserves nothing and charges nothing.
| Name | Required | Description | Default |
|---|---|---|---|
| plan_id | Yes | The plan id: a 26-character ULID as returned by list-plans or plan-trip, e.g. "01JVQ2S6D4X8N0RMB7YQZ5K3TA". Slugs and supplier codes are not accepted, and an id must never be invented. | |
| currency | No | Optional. ISO 4217 three-letter code the price is quoted in, e.g. "USD", "EUR", "GBP". Defaults to EUR. An unknown code falls back to EUR rather than failing. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | The plan id (a 26-character ULID). Pass it to get-plan, get-plan-coverage or create-checkout-session. Never invent one. |
| name | Yes | Plan name as a traveller sees it, e.g. "Spain 5GB". |
| type | Yes | What the plan sells: data only, or data plus a bundled voice and SMS allowance. |
| links | Yes | Where a person buys this plan on simfuse.app. |
| region | Yes | Raw region value for a regional plan, e.g. "Europe". Null for a country plan. |
| carrier | Yes | The mobile network this plan runs on, when we can name it. Null when we cannot. |
| country | Yes | The one country this plan is filed under. Null for a regional or worldwide plan. |
| network | Yes | The network name as plain text, or null when unknown. |
| currency | Yes | ISO 4217 code retail_price_cents is quoted in, e.g. "EUR". |
| operators | Yes | Network operators the plan roams on, as a list. Empty when none are published. |
| is_worldwide | Yes | True when the plan is sold as a worldwide bundle. |
| network_type | Yes | Fastest network generation the plan is sold as. |
| region_label | Yes | The region formatted for a person to read. Null for a country plan. |
| coverage_type | Yes | Scope of the plan: one country, a region, or worldwide. |
| validity_days | Yes | How many days the plan stays valid once it activates. |
| coverage_count | Yes | How many countries coverage_countries holds. |
| data_amount_mb | Yes | Data allowance in megabytes (1 GB is 1024 MB). 0 on an unlimited plan, where data_usage_policy carries the real terms. |
| excluded_count | Yes | How many countries excluded_countries holds. |
| supports_topup | Yes | Whether more data can be bought for the same eSIM once it runs low. |
| data_usage_policy | Yes | What the plan really gives you. Null when the supplier has never published its terms, which is different from having no limits. |
| coverage_countries | Yes | Every country the plan works in. |
| excluded_countries | Yes | Countries in this plan's own region that it does NOT cover. Always empty for a country plan and for a worldwide one. |
| retail_price_cents | Yes | Retail price in minor units (cents) of `currency`, so 1250 in EUR is 12.50 EUR. This is what a buyer pays for one eSIM. |
| supports_tethering | Yes | Whether hotspot or tethering is allowed. Null means no supplier has declared it, which is not the same as "no". |
| retail_prices_cents | No | Prices in other currencies, keyed by ISO 4217 code, in minor units. Only the multi-currency surfaces (the catalog export) carry one, so it is absent here: read retail_price_cents and currency instead. |
| data_restriction_type | Yes | Whether the allowance is capped ("limited") or unmetered ("unlimited"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered by structured data. The closing line ('reserves nothing and charges nothing') reinforces but does not materially extend that. It does usefully signal the fair-use-cap, hotspot, and top-up disclosure behavior, but the return format is left to the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action and the list of returned facts, followed by usage guidance and the alternative. No sentence is filler; the id and currency behaviors are folded into the schema rather than repeated in prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no prose explanation, and the description still names the returned fields at a high level. With the id format, currency fallback, sibling alternative, and safety profile all covered, an agent has everything required to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents the ULID format, the rejection of slugs/supplier codes, and the EUR fallback for unknown currency codes. The description only adds that the price is quoted 'in the currency you ask for', which is a marginal restatement of the currency parameter's purpose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Read everything about one eSIM plan by its id') and enumerates exactly which facts it returns. It is immediately distinguishable from list-plans, plan-trip, and get-plan-coverage.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use it (answering a specific question about an already-found plan, confirming before buying) and names the sibling to use instead when the question is coverage: 'Ask get-plan-coverage instead when the question is which countries it works in.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get-plan-coverageGet plan country coverageARead-onlyIdempotentInspect
List every country one eSIM plan works in, plus any country of its own region that it leaves out. Use it to answer "does this plan also cover Austria?" for a regional or worldwide plan, where the plan name says a region and the traveller needs the actual list. For a single-country plan the answer is that one country. Ask get-plan instead for the data allowance, validity or price. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| plan_id | Yes | The plan id: a 26-character ULID as returned by list-plans or plan-trip, e.g. "01JVQ2S6D4X8N0RMB7YQZ5K3TA". Slugs and supplier codes are not accepted, and an id must never be invented. |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | How many countries the plan covers. |
| countries | Yes | Every country the plan works in. Match on iso2 to answer "does this cover X?". |
| is_worldwide | Yes | True when the plan is sold as a worldwide bundle. |
| region_label | Yes | The plan's region written for a person, e.g. "Europe". Null for a country plan. |
| coverage_type | Yes | Scope of the plan: one country, a region, or worldwide. |
| total_excluded | Yes | How many countries of the plan's own region it does NOT cover. |
| excluded_countries | Yes | Countries in the plan's own region that it does not cover. Always empty for a country plan and for a worldwide one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is fully covered. The description adds the useful nuance that output includes both covered countries and countries omitted from a plan's own region, but this is essentially return-value semantics already carried by the output schema. Like the redundant 'Read-only' trailer, it adds limited value beyond structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core behavior in the first sentence, then routes usage and alternative. Nearly every clause earns its place, though the trailing 'Read-only' is redundant with readOnlyHint and could be dropped.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-param read tool with a full output schema and rich annotations, the description supplies everything an agent needs: purpose, usage context, edge-case behavior, and sibling routing. No material gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single plan_id parameter is thoroughly documented (ULID format, 26 chars, no slugs/supplier codes, never invent an id). The description contributes nothing about plan_id, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('list every country one eSIM plan works in') and even specifies the exact edge behavior (regional vs single-country plans). It distinguishes itself from its sibling get-plan by naming what get-plan covers instead. An agent can select this without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use case ('does this plan also cover Austria?' for regional/worldwide plans) and an explicit alternative with its scope ('Ask get-plan instead for the data allowance, validity or price'). The when-to-use and when-not-to-use routing is fully determined.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-destinationsList eSIM destinationsARead-onlyIdempotentInspect
Find the countries SimFuse sells eSIMs for, with the cheapest plan price ("from" price) for each in the currency you ask for. Start here when someone names a place: it turns "Portugal" into the two-letter country code the other tools take, and shows what that destination starts at. For one destination, follow it with list-plans; for a trip covering two or more countries, use plan-trip instead. Read-only, and it answers from the SimFuse catalog alone.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Optional. Maximum destinations to return, 1 to 300. Defaults to 300, which is the whole list. | |
| search | No | Optional. Match destinations by name, ISO 3166-1 alpha-2 or alpha-3 code, case-insensitively. A partial name works: "port" matches Portugal. Omit to list every destination. | |
| currency | No | Optional. ISO 4217 three-letter code the "from" prices are quoted in, e.g. "USD", "EUR", "GBP". Defaults to EUR. An unknown code falls back to EUR rather than failing. |
Output Schema
| Name | Required | Description |
|---|---|---|
| total | Yes | How many destinations matched, before `limit` was applied. |
| currency | Yes | ISO 4217 code every from_price_cents below is quoted in, e.g. "EUR". |
| returned | Yes | How many destinations are in this response. |
| destinations | Yes | The matching destinations. Empty when nothing matched. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and openWorldHint=false, so the safety profile is covered; the description still adds that it 'answers from the SimFuse catalog alone,' confirming there is no external lookup, and discloses the currency fallback behaviour. It does not add much beyond annotations and schema on pagination or response shape, keeping it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and payload in the first sentence, then routing guidance, then the read-only/catalog caveat. Four sentences, none redundant, and the most decision-relevant information comes first.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described. For a three-optional-parameter, read-only catalog tool, the description covers purpose, payload, routing to siblings, and safety context — nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the per-parameter documentation is already complete and the baseline is 3. The description adds workflow-level meaning: the search parameter is framed as the mechanism that 'turns "Portugal" into the two-letter country code the other tools take,' and currency is tied to the quoting of the 'from' price, which is more than the schema states.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource (list the countries SimFuse sells eSIMs for), plus the concrete payload (cheapest 'from' price per destination in the requested currency). It explicitly separates itself from list-plans (single destination) and plan-trip (multi-country), so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit trigger ('Start here when someone names a place') and names both alternatives with the conditions that select them: list-plans for one destination, plan-trip for two or more countries. When-to-use, when-to-switch, and alternatives are all present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-plansList eSIM plansARead-onlyIdempotentInspect
Show the eSIM plans on sale for one destination, or search the whole catalog, narrowing by data allowance, validity and price. Use it when the destination is already known and the traveller wants to compare what is available, or to find a plan inside a budget. Prices are live retail prices in the currency you ask for. For a trip covering two or more countries, use plan-trip first: it compares one plan for the whole route against one plan per country and picks the cheapest complete answer. Pass a plan id from here to get-plan, get-plan-coverage or create-checkout-session. Read-only, and it answers from the SimFuse catalog alone.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Optional. Maximum plans to return, 1 to 100. Defaults to 25. | |
| currency | No | Optional. ISO 4217 three-letter code prices are quoted and filtered in, e.g. "USD", "EUR", "GBP". Defaults to EUR. An unknown code falls back to EUR rather than failing. | |
| destination | No | Optional. ISO 3166-1 alpha-2 destination country code, e.g. "US", "GB", "DE". Look it up with list-destinations rather than guessing. Omit to search the whole catalog, including regional and worldwide plans. | |
| max_price_cents | No | Optional. Only plans at or below this retail price, in minor units (cents) of `currency`: 2500 is 25.00. | |
| min_price_cents | No | Optional. Only plans at or above this retail price, in minor units (cents) of `currency`: 500 is 5.00. | |
| max_validity_days | No | Optional. Only plans valid for at most this many days. | |
| min_validity_days | No | Optional. Only plans valid for at least this many days, e.g. 14 for a two-week trip. | |
| max_data_amount_mb | No | Optional. Only plans with at most this much data, in megabytes. | |
| min_data_amount_mb | No | Optional. Only plans with at least this much data, in MEGABYTES: 1 GB is 1024, 10 GB is 10240. |
Output Schema
| Name | Required | Description |
|---|---|---|
| plans | Yes | The matching plans. Empty when nothing matched. |
| matched | Yes | How many plans matched the filters, before `limit` was applied. |
| currency | Yes | ISO 4217 code every price below is quoted in, e.g. "EUR". |
| returned | Yes | How many plans are in this response. |
| truncated_by_candidate_cap | Yes | True when a catalog-wide search hit its internal candidate cap, so there are further matches this call could not see. Narrow it with a destination or a tighter data or validity filter rather than assuming you have seen everything. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description still adds real context beyond them: prices are live retail figures in the requested currency, and results come from the SimFuse catalog alone rather than live supplier inventory. It does not mention pagination behaviour or rate limits, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Five sentences, all load-bearing, with the core capability and the destination-vs-catalog scope front-loaded before the routing advice. It is slightly dense for a listing tool, but nothing is redundant with the schema or annotations, and the ordering is logical: what it does, when to use, how to use it, what to do next.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be explained, and all nine parameters are fully described in the schema. Combined with annotations covering safety and the description covering scope, alternatives and downstream chaining, an agent has everything needed to call this correctly or route elsewhere.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all nine parameters (including cents-based price bounds, validity days, data MB and currency) are self-documenting and the baseline is 3. The description adds a genuinely useful framing the schema does not: filtering happens against live retail prices in the currency you request, and the filter axes are enumerated as data allowance, validity and price.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Show the eSIM plans on sale') plus an explicit scope split: one destination versus the whole catalog. It distinguishes itself from siblings by naming plan-trip for multi-country trips and get-plan/get-plan-coverage/create-checkout-session as downstream consumers of the returned plan ids.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete when-to-use conditions (destination already known, traveller comparing, or budget hunting) and an explicit when-not/alternative: two or more countries should go through plan-trip first, with the reason (it compares one plan for the route against one per country). That is routing-level guidance, not inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
plan-tripPlan eSIMs for a tripARead-onlyIdempotentInspect
Answer "which eSIM should I buy for this trip?". Give it the stops, a country code and the days spent in each, and it compares one plan covering the whole route against one plan per country against a mix of the two, on live prices, then flags the cheapest option that covers everything and explains the choice in a sentence you can quote. It also estimates the data each stop needs, names any country SimFuse cannot cover, and returns package ids that go straight into create-checkout-session. Use it whenever a trip has two or more countries, and for a single country when the traveller wants a recommendation rather than a list. Read-only: nothing is reserved and nothing is charged, and the totals are today's catalog prices, not a quote held for later.
| Name | Required | Description | Default |
|---|---|---|---|
| start | No | Optional. Departure date as YYYY-MM-DD, e.g. "2026-04-18". Only used to date the stops in the answer; it does not change prices. Defaults to today. | |
| stops | Yes | The trip, one entry per country, in travel order. 1 to 12 stops, e.g. [{"country":"JP","days":7},{"country":"KR","days":5}]. | |
| usage | No | Optional. Trip-wide data usage for stops that do not set their own: "light" (about 300 MB a day), "regular" (about 800 MB a day) or "heavy" (about 2 GB a day). Defaults to "regular". | regular |
| currency | No | Optional. ISO 4217 three-letter code every price is quoted in, e.g. "USD", "EUR", "GBP". Defaults to EUR. An unknown code falls back to EUR rather than failing. |
Output Schema
| Name | Required | Description |
|---|---|---|
| trip | Yes | The trip as it was understood, which is worth reading back to the traveller. |
| reason | Yes | One sentence explaining the recommendation, written to be quoted to the traveller verbatim. |
| options | Yes | Every way of buying the trip that we could price, cheapest-first within each strategy. Empty when nothing we sell covers it. |
| checkout | Yes | How to act on the recommendation. |
| contract | Yes | Version of this answer's shape. "1" today; it only changes when an existing field changes meaning. |
| currency | Yes | ISO 4217 code every amount below is quoted in, e.g. "EUR". |
| warnings | Yes | Trip-level caveats: a country SimFuse does not sell, or a gap the recommended option leaves. Say these out loud rather than dropping them. |
| planner_url | Yes | The same trip on the SimFuse website, for a person who wants to finish it themselves. |
| recommendation | Yes | Which strategy won: one plan for the whole route, one plan per country, or a mix. Null when nothing we sell covers the trip. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds genuinely new behavioral context: nothing is reserved or charged, prices are today's catalog rates rather than a held quote, and the returned package ids flow directly into create-checkout-session. It also discloses the side finding that uncovered countries are named.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the question it answers, then capabilities, then usage guidance, then the read-only caveat. Efficient overall, though the middle sentence bundles several distinct outputs (cheapest option, data estimate, uncovered countries, package ids) into one long chain.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only planning tool with an output schema, the description covers the computation logic, the return payload shape, the read-only guarantee, and price freshness. Nothing an agent needs to decide whether or how to call it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema already documents every parameter including the usage enums, defaults, and country-code format. The description only restates 'the stops, a country code and the days spent in each' and adds no syntax or format detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with the exact question the tool answers ('which eSIM should I buy for this trip?') and states the specific computation: comparing one whole-route plan vs per-country vs a mix on live prices. It clearly distinguishes itself from siblings like list-plans and get-plan, which return catalog data rather than a recommendation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: 'Use it whenever a trip has two or more countries, and for a single country when the traveller wants a recommendation rather than a list.' That names both the trigger condition and the alternative (listing via list-plans), and it points to create-checkout-session as the downstream step.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
6 tool updates
- Changed
create-checkout-session12 fields changed- changed
Input schema / properties / agent_name / descriptionPrevious value: -"The name of the assistant opening the session, for the key record."New value: +"Optional. Name of the assistant or app opening the session, e.g. \"Claude\". Recorded on the agent key so we can tell integrations apart. Defaults to \"mcp-client\"." - added
Input schema / properties / agent_name / maxLengthAdded value: +100 - changed
Input schema / properties / buyer_email / descriptionPrevious value: -"Where the eSIM installation details are sent after payment. Strongly recommended."New value: +"Optional but strongly recommended. The traveller's email address, where the eSIM and its installation details are sent once payment settles. Ask for it rather than inventing one." - added
Input schema / properties / buyer_email / maxLengthAdded value: +255 - changed
Input schema / properties / currency / descriptionPrevious value: -"Three-letter currency code to charge in (e.g. \"USD\", \"EUR\"). Defaults to EUR."New value: +"Optional. ISO 4217 three-letter code to price the session in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. Every amount in the answer is minor units (cents) of this currency." - added
Input schema / properties / currency / maxLengthAdded value: +3 - added
Input schema / properties / currency / minLengthAdded value: +3 - added
Input schema / properties / items / descriptionAdded value: +"What to buy: one entry per plan, 1 to 50 entries. Pass the whole basket in one call, e.g. [{\"id\":\"01JVQ...\",\"quantity\":1}]." - changed
Input schema / properties / items / items / properties / id / descriptionPrevious value: -"A plan id from plan-trip, list-plans or the product feed. Never invented."New value: +"A plan id (26-character ULID) from plan-trip, list-plans, get-plan or the product feed, e.g. \"01JVQ2S6D4X8N0RMB7YQZ5K3TA\". Never invent one." - added
Input schema / properties / items / items / properties / id / maxLengthAdded value: +64 - added
Input schema / properties / items / items / properties / quantity / descriptionAdded value: +"How many of this plan to buy, 1 to 20. One eSIM per unit, so 2 means two separate eSIMs of the same plan (one traveller normally needs 1)." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "agent_key": { + "description": "The bearer key for every follow-up call on this session, shown ONCE and never again. Send it as \"Authorization: Bearer <key>\". It is a credential: use it, do not read it out to the traveller.", + "type": "string" + }, + "api": { + "description": "The HTTP endpoints for this session, all taking the agent_key as a bearer token.", + "properties": { + "cancel": { + "description": "POST here to cancel the session.", + "type": "string" + }, + "complete": { + "description": "POST here to complete the purchase, which is where payment happens.", + "type": "string" + }, + "session": { + "description": "GET this to re-read the session and its current totals.", + "type": "string" + } + }, + "required": [ + "session", + "complete", + "cancel" + ], + "type": "object" + }, + "note": { + "description": "How to use the key and how long the prices hold. Worth following literally.", + "type": "string" + }, + "session": { + "description": "The priced checkout session, in the same shape the agentic HTTP API returns it.", + "properties": { + "buyer": { + "description": "The buyer, when one was given. Null when no email was supplied, in which case ask for one before completing.", + "properties": { + "email": { + "description": "Where the eSIM is sent.", + "type": "string" + } + }, + "type": [ + "object", + "null" + ] + }, + "capabilities": { + "description": "What this session supports.", + "properties": { + "payment": { + "properties": { + "handlers": { + "description": "The ways this session can be paid.", + "items": { + "properties": { + "config": { + "description": "Handler-specific settings.", + "properties": { + "default_asset": { + "description": "Default asset for a crypto handler.", + "type": "string" + }, + "settlement": { + "description": "\"synchronous\" settles during completion; \"asynchronous\" settles later, so a 200 is not yet a purchase.", + "type": "string" + } + }, + "type": "object" + }, + "display_name": { + "description": "Handler written for a person.", + "type": "string" + }, + "id": { + "description": "Handler id to name when completing the session.", + "type": "string" + }, + "name": { + "description": "Fully qualified handler name.", + "type": "string" + }, + "psp": { + "description": "Which processor settles it.", + "type": "string" + }, + "requires_delegate_payment": { + "description": "Whether the agent must mint a delegated payment token first.", + "type": "boolean" + }, + "requires_pci_compliance": { + "description": "Whether card data passes through the agent.", + "type": "boolean" + }, + "spec": { + "description": "Where the handler is documented.", + "type": "string" + }, + "version": { + "description": "Handler version.", + "type": "string" + } + }, + "required": [ + "id", + "name", + "display_name", + "version", + "spec", + "requires_delegate_payment", + "requires_pci_compliance", + "psp", + "config" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "handlers" + ], + "type": "object" + } + }, + "required": [ + "payment" + ], + "type": "object" + }, + "created_at": { + "description": "ISO 8601 creation timestamp.", + "type": [ + "string", + "null" + ] + }, + "currency": { + "description": "Lower-case ISO 4217 code every amount is in, e.g. \"eur\".", + "type": "string" + }, + "expires_at": { + "description": "ISO 8601 timestamp after which this session can no longer be completed.", + "type": [ + "string", + "null" + ] + }, + "fulfillment_options": { + "description": "How the eSIM is delivered. Instant and free, stated explicitly so nobody has to guess whether shipping is coming.", + "items": { + "properties": { + "description": { + "description": "What the traveller receives, and when.", + "type": "string" + }, + "id": { + "description": "Option id.", + "type": "string" + }, + "title": { + "description": "Option title.", + "type": "string" + }, + "totals": { + "description": "What delivery costs. Always zero.", + "items": { + "description": "The delivery line, always zero.", + "properties": { + "amount": { + "description": "Amount in minor units (cents) of the session currency. A discount is NEGATIVE, so the lines sum to the total.", + "type": "integer" + }, + "display_text": { + "description": "The line written for a person.", + "type": "string" + }, + "type": { + "description": "What this line is, e.g. \"subtotal\", \"discount\", \"total\".", + "type": "string" + } + }, + "required": [ + "type", + "display_text", + "amount" + ], + "type": "object" + }, + "type": "array" + }, + "type": { + "description": "Always \"digital\" here: an eSIM has nothing to ship.", + "type": "string" + } + }, + "required": [ + "type", + "id", + "title", + "description", + "totals" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "description": "Session id, used in every follow-up call.", + "type": "string" + }, + "line_items": { + "description": "One entry per plan in the basket.", + "items": { + "properties": { + "base_amount": { + "description": "Price of one unit, in minor units.", + "type": "integer" + }, + "id": { + "description": "Line id.", + "type": "string" + }, + "item": { + "properties": { + "id": { + "description": "The plan id bought on this line.", + "type": "string" + }, + "quantity": { + "description": "How many.", + "type": "integer" + } + }, + "required": [ + "id", + "quantity" + ], + "type": "object" + }, + "subtotal": { + "description": "Line subtotal, in minor units.", + "type": "integer" + }, + "title": { + "description": "Plan name, for display.", + "type": [ + "string", + "null" + ] + }, + "total": { + "description": "Line total, in minor units.", + "type": "integer" + } + }, + "required": [ + "id", + "item", + "base_amount", + "subtotal", + "total", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "links": { + "description": "Seller policies, for a buyer who asks.", + "items": { + "properties": { + "type": { + "description": "Which document this is, e.g. \"terms_of_use\".", + "type": "string" + }, + "url": { + "description": "Where it lives.", + "type": "string" + } + }, + "required": [ + "type", + "url" + ], + "type": "object" + }, + "type": "array" + }, + "messages": { + "description": "Anything the agent must read before completing: payment instructions, a gateway minimum this basket does not clear, or a warning that settlement is still pending.", + "items": { + "properties": { + "code": { + "description": "Machine-readable message code, e.g. \"payment_instructions\", \"below_payment_minimum\", \"awaiting_settlement\".", + "type": "string" + }, + "content": { + "description": "The message itself. Payment instructions arrive here as fields (address, exact amount, memo): pass them through EXACTLY, never reformatted or rounded.", + "type": [ + "object", + "string" + ] + }, + "content_type": { + "description": "\"application/json\" when `content` is an object, \"text/plain\" when it is a sentence.", + "type": "string" + }, + "type": { + "description": "Whether this is information or a caution.", + "enum": [ + "info", + "warning" + ], + "type": "string" + } + }, + "required": [ + "type", + "code", + "content_type", + "content" + ], + "type": "object" + }, + "type": "array" + }, + "order": { + "description": "The order this session produced, once it has one. Null until then.", + "properties": { + "id": { + "description": "The order id.", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": [ + "object", + "null" + ] + }, + "payment_handler_id": { + "description": "The handler this session will settle through.", + "type": [ + "string", + "null" + ] + }, + "price_locked_until": { + "description": "ISO 8601 timestamp until which these totals hold. After it, re-read the session for fresh totals rather than quoting these.", + "type": [ + "string", + "null" + ] + }, + "protocol": { + "description": "Agentic Commerce Protocol version this session speaks.", + "type": "string" + }, + "status": { + "description": "Where the session is: \"ready_for_payment\" means it can be completed; \"complete_in_progress\" means payment has not settled yet and the purchase is NOT done; \"completed\" means the eSIM is on its way. Also \"incomplete\", \"not_ready_for_payment\", \"canceled\" and \"expired\".", + "type": "string" + }, + "totals": { + "description": "The money, ordered so the lines read down to the total.", + "items": { + "description": "One money line.", + "properties": { + "amount": { + "description": "Amount in minor units (cents) of the session currency. A discount is NEGATIVE, so the lines sum to the total.", + "type": "integer" + }, + "display_text": { + "description": "The line written for a person.", + "type": "string" + }, + "type": { + "description": "What this line is, e.g. \"subtotal\", \"discount\", \"total\".", + "type": "string" + } + }, + "required": [ + "type", + "display_text", + "amount" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "ISO 8601 update timestamp.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "id", + "protocol", + "status", + "currency", + "line_items", + "totals", + "fulfillment_options", + "capabilities", + "buyer", + "payment_handler_id", + "messages", + "links", + "expires_at", + "price_locked_until", + "order", + "created_at", + "updated_at" + ], + "type": "object" + } + }, + "required": [ + "session", + "agent_key", + "api", + "note" + ], + "type": "object" +}
- Changed
get-plan5 fields changed- changed
Input schema / properties / currency / descriptionPrevious value: -"Three-letter currency code for the price (e.g. \"USD\", \"EUR\"). Defaults to EUR."New value: +"Optional. ISO 4217 three-letter code the price is quoted in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. An unknown code falls back to EUR rather than failing." - added
Input schema / properties / currency / maxLengthAdded value: +3 - added
Input schema / properties / currency / minLengthAdded value: +3 - changed
Input schema / properties / plan_id / descriptionPrevious value: -"The plan id (a ULID) as returned by list-plans."New value: +"The plan id: a 26-character ULID as returned by list-plans or plan-trip, e.g. \"01JVQ2S6D4X8N0RMB7YQZ5K3TA\". Slugs and supplier codes are not accepted, and an id must never be invented." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "carrier": { + "description": "The mobile network this plan runs on, when we can name it. Null when we cannot.", + "properties": { + "logo_url": { + "description": "Carrier logo image URL.", + "type": "string" + }, + "name": { + "description": "Carrier name, e.g. \"KPN\".", + "type": "string" + } + }, + "required": [ + "name", + "logo_url" + ], + "type": [ + "object", + "null" + ] + }, + "country": { + "description": "The one country this plan is filed under. Null for a regional or worldwide plan.", + "properties": { + "currency": { + "description": "ISO 4217 code the from_price_cents beside it is expressed in, which is the currency you asked for, e.g. \"EUR\". Null exactly when from_price_cents is null, which is what a country nested on a plan answers: nothing priced it there.", + "type": [ + "string", + "null" + ] + }, + "from_price_cents": { + "description": "Cheapest plan for this destination, in minor units (cents) of the response currency, so 1250 is 12.50. Null when this response did not price the destination.", + "type": [ + "integer", + "null" + ] + }, + "iso2": { + "description": "ISO 3166-1 alpha-2 code, e.g. \"ES\". This is the code list-plans and plan-trip take.", + "type": "string" + }, + "iso3": { + "description": "ISO 3166-1 alpha-3 code, e.g. \"ESP\".", + "type": "string" + }, + "links": { + "properties": { + "country": { + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for this country's storefront page. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": "object" + } + }, + "required": [ + "country" + ], + "type": "object" + }, + "name": { + "description": "English country name, e.g. \"Spain\".", + "type": "string" + }, + "region": { + "description": "The region this country is filed under, e.g. \"Europe\". Null when it is filed under none.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "iso2", + "iso3", + "region", + "from_price_cents", + "currency", + "links" + ], + "type": [ + "object", + "null" + ] + }, + "coverage_count": { + "description": "How many countries coverage_countries holds.", + "type": "integer" + }, + "coverage_countries": { + "description": "Every country the plan works in.", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code, or null for a country we could not match to a code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name.", + "type": "string" + }, + "operators": { + "description": "Networks in that country, when the country could be attributed. Empty means not attributed, never \"no coverage\".", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "iso2", + "operators" + ], + "type": "object" + }, + "type": "array" + }, + "coverage_type": { + "description": "Scope of the plan: one country, a region, or worldwide.", + "enum": [ + "country", + "region", + "global" + ], + "type": "string" + }, + "currency": { + "description": "ISO 4217 code retail_price_cents is quoted in, e.g. \"EUR\".", + "type": [ + "string", + "null" + ] + }, + "data_amount_mb": { + "description": "Data allowance in megabytes (1 GB is 1024 MB). 0 on an unlimited plan, where data_usage_policy carries the real terms.", + "type": "integer" + }, + "data_restriction_type": { + "description": "Whether the allowance is capped (\"limited\") or unmetered (\"unlimited\").", + "enum": [ + "limited", + "unlimited" + ], + "type": "string" + }, + "data_usage_policy": { + "description": "What the plan really gives you. Null when the supplier has never published its terms, which is different from having no limits.", + "properties": { + "high_speed_data_mb": { + "description": "Full-speed allowance in megabytes PER RESET PERIOD, so 1 GB a day for 30 days is 1024, not 30720. 0 means genuinely uncapped.", + "type": [ + "integer", + "null" + ] + }, + "max_speed_kbps": { + "description": "Speed ceiling in kbit/s from the first megabyte. Null means no ceiling.", + "type": [ + "integer", + "null" + ] + }, + "reduced_speed_kbps": { + "description": "Speed in kbit/s after the full-speed allowance is used. Null means the data STOPS rather than slowing down.", + "type": [ + "integer", + "null" + ] + }, + "reset_period": { + "description": "How often the full-speed allowance resets. Null means it covers the whole plan.", + "enum": [ + "daily", + "weekly", + "monthly", + null + ], + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "high_speed_data_mb", + "reset_period", + "max_speed_kbps", + "reduced_speed_kbps" + ], + "type": [ + "object", + "null" + ] + }, + "excluded_count": { + "description": "How many countries excluded_countries holds.", + "type": "integer" + }, + "excluded_countries": { + "description": "Countries in this plan's own region that it does NOT cover. Always empty for a country plan and for a worldwide one.", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name.", + "type": "string" + } + }, + "required": [ + "name", + "iso2" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "description": "The plan id (a 26-character ULID). Pass it to get-plan, get-plan-coverage or create-checkout-session. Never invent one.", + "type": "string" + }, + "is_worldwide": { + "description": "True when the plan is sold as a worldwide bundle.", + "type": "boolean" + }, + "links": { + "description": "Where a person buys this plan on simfuse.app.", + "properties": { + "country": { + "description": "The country page on its own, or null when the plan has no single country.", + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for the plan's country page. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": [ + "object", + "null" + ] + }, + "plan": { + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for the page this plan is bought on, with the plan preselected. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": "object" + } + }, + "required": [ + "plan", + "country" + ], + "type": "object" + }, + "name": { + "description": "Plan name as a traveller sees it, e.g. \"Spain 5GB\".", + "type": "string" + }, + "network": { + "description": "The network name as plain text, or null when unknown.", + "type": [ + "string", + "null" + ] + }, + "network_type": { + "description": "Fastest network generation the plan is sold as.", + "enum": [ + "5G", + "LTE" + ], + "type": "string" + }, + "operators": { + "description": "Network operators the plan roams on, as a list. Empty when none are published.", + "items": { + "type": "string" + }, + "type": "array" + }, + "region": { + "description": "Raw region value for a regional plan, e.g. \"Europe\". Null for a country plan.", + "type": [ + "string", + "null" + ] + }, + "region_label": { + "description": "The region formatted for a person to read. Null for a country plan.", + "type": [ + "string", + "null" + ] + }, + "retail_price_cents": { + "description": "Retail price in minor units (cents) of `currency`, so 1250 in EUR is 12.50 EUR. This is what a buyer pays for one eSIM.", + "type": [ + "integer", + "null" + ] + }, + "retail_prices_cents": { + "description": "Prices in other currencies, keyed by ISO 4217 code, in minor units. Only the multi-currency surfaces (the catalog export) carry one, so it is absent here: read retail_price_cents and currency instead.", + "type": "object" + }, + "supports_tethering": { + "description": "Whether hotspot or tethering is allowed. Null means no supplier has declared it, which is not the same as \"no\".", + "type": [ + "boolean", + "null" + ] + }, + "supports_topup": { + "description": "Whether more data can be bought for the same eSIM once it runs low.", + "type": "boolean" + }, + "type": { + "description": "What the plan sells: data only, or data plus a bundled voice and SMS allowance.", + "enum": [ + "data", + "data_voice_sms" + ], + "type": "string" + }, + "validity_days": { + "description": "How many days the plan stays valid once it activates.", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "carrier", + "network", + "operators", + "data_amount_mb", + "data_usage_policy", + "validity_days", + "type", + "data_restriction_type", + "coverage_type", + "region", + "region_label", + "is_worldwide", + "coverage_countries", + "coverage_count", + "excluded_countries", + "excluded_count", + "retail_price_cents", + "currency", + "supports_topup", + "supports_tethering", + "network_type", + "country", + "links" + ], + "type": "object" +}
- Changed
get-plan-coverage2 fields changed- changed
Input schema / properties / plan_id / descriptionPrevious value: -"The plan id (a ULID) as returned by list-plans."New value: +"The plan id: a 26-character ULID as returned by list-plans or plan-trip, e.g. \"01JVQ2S6D4X8N0RMB7YQZ5K3TA\". Slugs and supplier codes are not accepted, and an id must never be invented." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "countries": { + "description": "Every country the plan works in. Match on iso2 to answer \"does this cover X?\".", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code, or null for a country we could not match to a code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name, e.g. \"Spain\".", + "type": "string" + } + }, + "required": [ + "name", + "iso2" + ], + "type": "object" + }, + "type": "array" + }, + "coverage_type": { + "description": "Scope of the plan: one country, a region, or worldwide.", + "enum": [ + "country", + "region", + "global" + ], + "type": "string" + }, + "excluded_countries": { + "description": "Countries in the plan's own region that it does not cover. Always empty for a country plan and for a worldwide one.", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code, or null for a country we could not match to a code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name, e.g. \"Spain\".", + "type": "string" + } + }, + "required": [ + "name", + "iso2" + ], + "type": "object" + }, + "type": "array" + }, + "is_worldwide": { + "description": "True when the plan is sold as a worldwide bundle.", + "type": "boolean" + }, + "region_label": { + "description": "The plan's region written for a person, e.g. \"Europe\". Null for a country plan.", + "type": [ + "string", + "null" + ] + }, + "total": { + "description": "How many countries the plan covers.", + "type": "integer" + }, + "total_excluded": { + "description": "How many countries of the plan's own region it does NOT cover.", + "type": "integer" + } + }, + "required": [ + "coverage_type", + "region_label", + "is_worldwide", + "total", + "countries", + "total_excluded", + "excluded_countries" + ], + "type": "object" +}
- Changed
list-destinations9 fields changed- changed
Input schema / properties / currency / descriptionPrevious value: -"Three-letter currency code for the \"from\" prices (e.g. \"USD\", \"EUR\"). Defaults to EUR."New value: +"Optional. ISO 4217 three-letter code the \"from\" prices are quoted in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. An unknown code falls back to EUR rather than failing." - added
Input schema / properties / currency / maxLengthAdded value: +3 - added
Input schema / properties / currency / minLengthAdded value: +3 - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum destinations to return, 1-300. Defaults to 300."New value: +"Optional. Maximum destinations to return, 1 to 300. Defaults to 300, which is the whole list." - added
Input schema / properties / limit / maximumAdded value: +300 - added
Input schema / properties / limit / minimumAdded value: +1 - changed
Input schema / properties / search / descriptionPrevious value: -"Optional. Match destinations by name or country code, case-insensitively. A partial name works (\"port\" matches Portugal)."New value: +"Optional. Match destinations by name, ISO 3166-1 alpha-2 or alpha-3 code, case-insensitively. A partial name works: \"port\" matches Portugal. Omit to list every destination." - added
Input schema / properties / search / maxLengthAdded value: +100 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "currency": { + "description": "ISO 4217 code every from_price_cents below is quoted in, e.g. \"EUR\".", + "type": "string" + }, + "destinations": { + "description": "The matching destinations. Empty when nothing matched.", + "items": { + "properties": { + "currency": { + "description": "ISO 4217 code the from_price_cents beside it is expressed in, which is the currency you asked for, e.g. \"EUR\". Null exactly when from_price_cents is null, which is what a country nested on a plan answers: nothing priced it there.", + "type": [ + "string", + "null" + ] + }, + "from_price_cents": { + "description": "Cheapest plan for this destination, in minor units (cents) of the response currency, so 1250 is 12.50. Null when this response did not price the destination.", + "type": [ + "integer", + "null" + ] + }, + "iso2": { + "description": "ISO 3166-1 alpha-2 code, e.g. \"ES\". This is the code list-plans and plan-trip take.", + "type": "string" + }, + "iso3": { + "description": "ISO 3166-1 alpha-3 code, e.g. \"ESP\".", + "type": "string" + }, + "links": { + "properties": { + "country": { + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for this country's storefront page. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": "object" + } + }, + "required": [ + "country" + ], + "type": "object" + }, + "name": { + "description": "English country name, e.g. \"Spain\".", + "type": "string" + }, + "region": { + "description": "The region this country is filed under, e.g. \"Europe\". Null when it is filed under none.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "iso2", + "iso3", + "region", + "from_price_cents", + "currency", + "links" + ], + "type": "object" + }, + "type": "array" + }, + "returned": { + "description": "How many destinations are in this response.", + "type": "integer" + }, + "total": { + "description": "How many destinations matched, before `limit` was applied.", + "type": "integer" + } + }, + "required": [ + "total", + "returned", + "currency", + "destinations" + ], + "type": "object" +}
- Changed
list-plans20 fields changed- changed
Input schema / properties / currency / descriptionPrevious value: -"Three-letter currency code for prices (e.g. \"USD\", \"EUR\"). Defaults to EUR."New value: +"Optional. ISO 4217 three-letter code prices are quoted and filtered in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. An unknown code falls back to EUR rather than failing." - added
Input schema / properties / currency / maxLengthAdded value: +3 - added
Input schema / properties / currency / minLengthAdded value: +3 - changed
Input schema / properties / destination / descriptionPrevious value: -"Optional. Two-letter destination country code (e.g. \"US\", \"GB\", \"DE\"). Omit to search the whole catalog, including regional and worldwide plans."New value: +"Optional. ISO 3166-1 alpha-2 destination country code, e.g. \"US\", \"GB\", \"DE\". Look it up with list-destinations rather than guessing. Omit to search the whole catalog, including regional and worldwide plans." - added
Input schema / properties / destination / maxLengthAdded value: +2 - added
Input schema / properties / destination / minLengthAdded value: +2 - changed
Input schema / properties / limit / descriptionPrevious value: -"Maximum plans to return, 1-100. Defaults to 25."New value: +"Optional. Maximum plans to return, 1 to 100. Defaults to 25." - added
Input schema / properties / limit / maximumAdded value: +100 - added
Input schema / properties / limit / minimumAdded value: +1 - added
Input schema / properties / max_data_amount_mb / minimumAdded value: +0 - changed
Input schema / properties / max_price_cents / descriptionPrevious value: -"Optional. Only plans at or below this retail price, in minor units of the requested currency."New value: +"Optional. Only plans at or below this retail price, in minor units (cents) of `currency`: 2500 is 25.00." - added
Input schema / properties / max_price_cents / minimumAdded value: +0 - added
Input schema / properties / max_validity_days / minimumAdded value: +0 - changed
Input schema / properties / min_data_amount_mb / descriptionPrevious value: -"Optional. Only plans with at least this much data, in megabytes (1 GB = 1024 MB)."New value: +"Optional. Only plans with at least this much data, in MEGABYTES: 1 GB is 1024, 10 GB is 10240." - added
Input schema / properties / min_data_amount_mb / minimumAdded value: +0 - changed
Input schema / properties / min_price_cents / descriptionPrevious value: -"Optional. Only plans at or above this retail price, in minor units of the requested currency (e.g. 500 = 5.00)."New value: +"Optional. Only plans at or above this retail price, in minor units (cents) of `currency`: 500 is 5.00." - added
Input schema / properties / min_price_cents / minimumAdded value: +0 - changed
Input schema / properties / min_validity_days / descriptionPrevious value: -"Optional. Only plans valid for at least this many days."New value: +"Optional. Only plans valid for at least this many days, e.g. 14 for a two-week trip." - added
Input schema / properties / min_validity_days / minimumAdded value: +0 - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "currency": { + "description": "ISO 4217 code every price below is quoted in, e.g. \"EUR\".", + "type": "string" + }, + "matched": { + "description": "How many plans matched the filters, before `limit` was applied.", + "type": "integer" + }, + "plans": { + "description": "The matching plans. Empty when nothing matched.", + "items": { + "properties": { + "carrier": { + "description": "The mobile network this plan runs on, when we can name it. Null when we cannot.", + "properties": { + "logo_url": { + "description": "Carrier logo image URL.", + "type": "string" + }, + "name": { + "description": "Carrier name, e.g. \"KPN\".", + "type": "string" + } + }, + "required": [ + "name", + "logo_url" + ], + "type": [ + "object", + "null" + ] + }, + "country": { + "description": "The one country this plan is filed under. Null for a regional or worldwide plan.", + "properties": { + "currency": { + "description": "ISO 4217 code the from_price_cents beside it is expressed in, which is the currency you asked for, e.g. \"EUR\". Null exactly when from_price_cents is null, which is what a country nested on a plan answers: nothing priced it there.", + "type": [ + "string", + "null" + ] + }, + "from_price_cents": { + "description": "Cheapest plan for this destination, in minor units (cents) of the response currency, so 1250 is 12.50. Null when this response did not price the destination.", + "type": [ + "integer", + "null" + ] + }, + "iso2": { + "description": "ISO 3166-1 alpha-2 code, e.g. \"ES\". This is the code list-plans and plan-trip take.", + "type": "string" + }, + "iso3": { + "description": "ISO 3166-1 alpha-3 code, e.g. \"ESP\".", + "type": "string" + }, + "links": { + "properties": { + "country": { + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for this country's storefront page. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": "object" + } + }, + "required": [ + "country" + ], + "type": "object" + }, + "name": { + "description": "English country name, e.g. \"Spain\".", + "type": "string" + }, + "region": { + "description": "The region this country is filed under, e.g. \"Europe\". Null when it is filed under none.", + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "name", + "iso2", + "iso3", + "region", + "from_price_cents", + "currency", + "links" + ], + "type": [ + "object", + "null" + ] + }, + "coverage_count": { + "description": "How many countries coverage_countries holds.", + "type": "integer" + }, + "coverage_countries": { + "description": "Every country the plan works in.", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code, or null for a country we could not match to a code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name.", + "type": "string" + }, + "operators": { + "description": "Networks in that country, when the country could be attributed. Empty means not attributed, never \"no coverage\".", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "name", + "iso2", + "operators" + ], + "type": "object" + }, + "type": "array" + }, + "coverage_type": { + "description": "Scope of the plan: one country, a region, or worldwide.", + "enum": [ + "country", + "region", + "global" + ], + "type": "string" + }, + "currency": { + "description": "ISO 4217 code retail_price_cents is quoted in, e.g. \"EUR\".", + "type": [ + "string", + "null" + ] + }, + "data_amount_mb": { + "description": "Data allowance in megabytes (1 GB is 1024 MB). 0 on an unlimited plan, where data_usage_policy carries the real terms.", + "type": "integer" + }, + "data_restriction_type": { + "description": "Whether the allowance is capped (\"limited\") or unmetered (\"unlimited\").", + "enum": [ + "limited", + "unlimited" + ], + "type": "string" + }, + "data_usage_policy": { + "description": "What the plan really gives you. Null when the supplier has never published its terms, which is different from having no limits.", + "properties": { + "high_speed_data_mb": { + "description": "Full-speed allowance in megabytes PER RESET PERIOD, so 1 GB a day for 30 days is 1024, not 30720. 0 means genuinely uncapped.", + "type": [ + "integer", + "null" + ] + }, + "max_speed_kbps": { + "description": "Speed ceiling in kbit/s from the first megabyte. Null means no ceiling.", + "type": [ + "integer", + "null" + ] + }, + "reduced_speed_kbps": { + "description": "Speed in kbit/s after the full-speed allowance is used. Null means the data STOPS rather than slowing down.", + "type": [ + "integer", + "null" + ] + }, + "reset_period": { + "description": "How often the full-speed allowance resets. Null means it covers the whole plan.", + "enum": [ + "daily", + "weekly", + "monthly", + null + ], + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "high_speed_data_mb", + "reset_period", + "max_speed_kbps", + "reduced_speed_kbps" + ], + "type": [ + "object", + "null" + ] + }, + "excluded_count": { + "description": "How many countries excluded_countries holds.", + "type": "integer" + }, + "excluded_countries": { + "description": "Countries in this plan's own region that it does NOT cover. Always empty for a country plan and for a worldwide one.", + "items": { + "properties": { + "iso2": { + "description": "ISO 3166-1 alpha-2 code.", + "type": [ + "string", + "null" + ] + }, + "name": { + "description": "English country name.", + "type": "string" + } + }, + "required": [ + "name", + "iso2" + ], + "type": "object" + }, + "type": "array" + }, + "id": { + "description": "The plan id (a 26-character ULID). Pass it to get-plan, get-plan-coverage or create-checkout-session. Never invent one.", + "type": "string" + }, + "is_worldwide": { + "description": "True when the plan is sold as a worldwide bundle.", + "type": "boolean" + }, + "links": { + "description": "Where a person buys this plan on simfuse.app.", + "properties": { + "country": { + "description": "The country page on its own, or null when the plan has no single country.", + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for the plan's country page. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": [ + "object", + "null" + ] + }, + "plan": { + "properties": { + "path": { + "description": "Path on the storefront, e.g. \"/esim/es\".", + "type": "string" + }, + "query": { + "description": "Query parameters that belong on the path, as an object. Empty when there are none.", + "type": "object" + }, + "url": { + "description": "The full storefront URL for the page this plan is bought on, with the plan preselected. Safe to show to a person.", + "type": "string" + } + }, + "required": [ + "path", + "query", + "url" + ], + "type": "object" + } + }, + "required": [ + "plan", + "country" + ], + "type": "object" + }, + "name": { + "description": "Plan name as a traveller sees it, e.g. \"Spain 5GB\".", + "type": "string" + }, + "network": { + "description": "The network name as plain text, or null when unknown.", + "type": [ + "string", + "null" + ] + }, + "network_type": { + "description": "Fastest network generation the plan is sold as.", + "enum": [ + "5G", + "LTE" + ], + "type": "string" + }, + "operators": { + "description": "Network operators the plan roams on, as a list. Empty when none are published.", + "items": { + "type": "string" + }, + "type": "array" + }, + "region": { + "description": "Raw region value for a regional plan, e.g. \"Europe\". Null for a country plan.", + "type": [ + "string", + "null" + ] + }, + "region_label": { + "description": "The region formatted for a person to read. Null for a country plan.", + "type": [ + "string", + "null" + ] + }, + "retail_price_cents": { + "description": "Retail price in minor units (cents) of `currency`, so 1250 in EUR is 12.50 EUR. This is what a buyer pays for one eSIM.", + "type": [ + "integer", + "null" + ] + }, + "retail_prices_cents": { + "description": "Prices in other currencies, keyed by ISO 4217 code, in minor units. Only the multi-currency surfaces (the catalog export) carry one, so it is absent here: read retail_price_cents and currency instead.", + "type": "object" + }, + "supports_tethering": { + "description": "Whether hotspot or tethering is allowed. Null means no supplier has declared it, which is not the same as \"no\".", + "type": [ + "boolean", + "null" + ] + }, + "supports_topup": { + "description": "Whether more data can be bought for the same eSIM once it runs low.", + "type": "boolean" + }, + "type": { + "description": "What the plan sells: data only, or data plus a bundled voice and SMS allowance.", + "enum": [ + "data", + "data_voice_sms" + ], + "type": "string" + }, + "validity_days": { + "description": "How many days the plan stays valid once it activates.", + "type": "integer" + } + }, + "required": [ + "id", + "name", + "carrier", + "network", + "operators", + "data_amount_mb", + "data_usage_policy", + "validity_days", + "type", + "data_restriction_type", + "coverage_type", + "region", + "region_label", + "is_worldwide", + "coverage_countries", + "coverage_count", + "excluded_countries", + "excluded_count", + "retail_price_cents", + "currency", + "supports_topup", + "supports_tethering", + "network_type", + "country", + "links" + ], + "type": "object" + }, + "type": "array" + }, + "returned": { + "description": "How many plans are in this response.", + "type": "integer" + }, + "truncated_by_candidate_cap": { + "description": "True when a catalog-wide search hit its internal candidate cap, so there are further matches this call could not see. Narrow it with a destination or a tighter data or validity filter rather than assuming you have seen everything.", + "type": "boolean" + } + }, + "required": [ + "matched", + "returned", + "currency", + "truncated_by_candidate_cap", + "plans" + ], + "type": "object" +}
- Changed
plan-trip15 fields changed- changed
Input schema / properties / currency / descriptionPrevious value: -"Three-letter currency code for pricing (e.g. \"USD\", \"EUR\"). Defaults to the visitor-neutral base currency."New value: +"Optional. ISO 4217 three-letter code every price is quoted in, e.g. \"USD\", \"EUR\", \"GBP\". Defaults to EUR. An unknown code falls back to EUR rather than failing." - added
Input schema / properties / currency / maxLengthAdded value: +3 - added
Input schema / properties / currency / minLengthAdded value: +3 - changed
Input schema / properties / start / descriptionPrevious value: -"Departure date as YYYY-MM-DD. Defaults to today."New value: +"Optional. Departure date as YYYY-MM-DD, e.g. \"2026-04-18\". Only used to date the stops in the answer; it does not change prices. Defaults to today." - added
Input schema / properties / start / maxLengthAdded value: +10 - added
Input schema / properties / start / minLengthAdded value: +10 - changed
Input schema / properties / stops / descriptionPrevious value: -"The trip, one entry per country, in travel order."New value: +"The trip, one entry per country, in travel order. 1 to 12 stops, e.g. [{\"country\":\"JP\",\"days\":7},{\"country\":\"KR\",\"days\":5}]." - changed
Input schema / properties / stops / items / properties / country / descriptionPrevious value: -"Two-letter ISO country code, e.g. \"JP\"."New value: +"ISO 3166-1 alpha-2 country code, e.g. \"JP\" for Japan. Look one up with list-destinations rather than guessing. Each country may appear once: give one stop with the total days rather than two visits." - added
Input schema / properties / stops / items / properties / country / maxLengthAdded value: +2 - added
Input schema / properties / stops / items / properties / country / minLengthAdded value: +2 - changed
Input schema / properties / stops / items / properties / days / descriptionPrevious value: -"Days spent in that country, 1-365."New value: +"Days spent in that country, 1 to 365. Count the nights of the stay." - changed
Input schema / properties / stops / items / properties / usage / descriptionPrevious value: -"How heavily data is used during this stop. Overrides the trip-wide usage."New value: +"Optional. How heavily data is used during this stop: \"light\" (about 300 MB a day, maps and messaging), \"regular\" (about 800 MB a day) or \"heavy\" (about 2 GB a day, video and hotspot). Overrides the trip-wide `usage` for this stop only." - added
Input schema / properties / usage / defaultAdded value: +"regular" - changed
Input schema / properties / usage / descriptionPrevious value: -"Trip-wide data usage for stops that do not set their own. Defaults to regular (about 800 MB/day)."New value: +"Optional. Trip-wide data usage for stops that do not set their own: \"light\" (about 300 MB a day), \"regular\" (about 800 MB a day) or \"heavy\" (about 2 GB a day). Defaults to \"regular\"." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "properties": { + "checkout": { + "description": "How to act on the recommendation.", + "properties": { + "checkout_sessions": { + "description": "HTTP endpoint that opens a checkout session, if you would rather not use the create-checkout-session tool.", + "type": "string" + }, + "human_url": { + "description": "Where to send a person to buy this themselves.", + "type": "string" + }, + "items": { + "description": "The recommended option as checkout line items, ready to pass to create-checkout-session. Null when nothing covers the trip.", + "items": { + "properties": { + "id": { + "description": "Plan id.", + "type": "string" + }, + "quantity": { + "description": "How many to buy.", + "type": "integer" + } + }, + "required": [ + "id", + "quantity" + ], + "type": "object" + }, + "type": [ + "array", + "null" + ] + }, + "note": { + "description": "What the totals are and are not: catalog prices today, never a reservation.", + "type": "string" + }, + "register": { + "description": "HTTP endpoint that mints an agent key for that API.", + "type": "string" + } + }, + "required": [ + "items", + "checkout_sessions", + "register", + "human_url", + "note" + ], + "type": "object" + }, + "contract": { + "description": "Version of this answer's shape. \"1\" today; it only changes when an existing field changes meaning.", + "type": "string" + }, + "currency": { + "description": "ISO 4217 code every amount below is quoted in, e.g. \"EUR\".", + "type": "string" + }, + "options": { + "description": "Every way of buying the trip that we could price, cheapest-first within each strategy. Empty when nothing we sell covers it.", + "items": { + "properties": { + "complete": { + "description": "True when this option covers every stop. False means at least one stop is left without data.", + "type": "boolean" + }, + "esims": { + "description": "How many eSIMs the traveller installs under this option.", + "type": "integer" + }, + "items": { + "description": "The plans this option buys.", + "items": { + "properties": { + "covers": { + "description": "ISO 3166-1 alpha-2 codes of the stops this line covers.", + "items": { + "type": "string" + }, + "type": "array" + }, + "data": { + "description": "Allowance written for a person, e.g. \"5 GB\" or \"Unlimited\".", + "type": "string" + }, + "data_mb": { + "description": "Allowance in megabytes. 0 on an unlimited plan, where `policy` carries the real terms.", + "type": [ + "integer", + "null" + ] + }, + "name": { + "description": "Plan name as a traveller sees it.", + "type": "string" + }, + "package_id": { + "description": "The plan id to buy. Pass it to create-checkout-session or get-plan.", + "type": "string" + }, + "policy": { + "description": "What the plan really gives you. Null when the supplier has never published its terms, which is different from having no limits.", + "properties": { + "high_speed_data_mb": { + "description": "Full-speed allowance in megabytes PER RESET PERIOD, so 1 GB a day for 30 days is 1024, not 30720. 0 means genuinely uncapped.", + "type": [ + "integer", + "null" + ] + }, + "max_speed_kbps": { + "description": "Speed ceiling in kbit/s from the first megabyte. Null means no ceiling.", + "type": [ + "integer", + "null" + ] + }, + "reduced_speed_kbps": { + "description": "Speed in kbit/s after the full-speed allowance is used. Null means the data STOPS rather than slowing down.", + "type": [ + "integer", + "null" + ] + }, + "reset_period": { + "description": "How often the full-speed allowance resets. Null means it covers the whole plan.", + "enum": [ + "daily", + "weekly", + "monthly", + null + ], + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "high_speed_data_mb", + "reset_period", + "max_speed_kbps", + "reduced_speed_kbps" + ], + "type": [ + "object", + "null" + ] + }, + "price": { + "description": "The same price formatted for a person.", + "type": "string" + }, + "price_cents": { + "description": "Price for one of this plan, in minor units (cents) of the response currency.", + "type": "integer" + }, + "quantity": { + "description": "How many of this plan to buy.", + "type": "integer" + }, + "unlimited": { + "description": "True when the plan is sold as unlimited, which almost always means unlimited up to a fair-use cap.", + "type": "boolean" + }, + "validity_days": { + "description": "How many days the plan stays valid once it activates.", + "type": "integer" + } + }, + "required": [ + "package_id", + "name", + "covers", + "quantity", + "data", + "data_mb", + "unlimited", + "validity_days", + "policy", + "price_cents", + "price" + ], + "type": "object" + }, + "type": "array" + }, + "purchasable": { + "description": "False when the option needs more eSIMs than one order can carry.", + "type": "boolean" + }, + "recommended": { + "description": "True on the one option this answer recommends.", + "type": "boolean" + }, + "saves_cents": { + "description": "What this option saves against the next cheapest complete alternative, in minor units. 0 when there is none or when it is dearer.", + "type": "integer" + }, + "strategy": { + "description": "How this option buys the trip.", + "enum": [ + "single", + "per_country", + "mixed" + ], + "type": "string" + }, + "total": { + "description": "The same total formatted for a person, e.g. \"24.50 EUR\".", + "type": "string" + }, + "total_cents": { + "description": "Total price in minor units (cents) of the response currency, so 2450 is 24.50.", + "type": "integer" + }, + "warnings": { + "description": "What this option does not do: a stop it leaves uncovered, a plan that runs out or expires early. Empty when there is nothing to say.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "strategy", + "recommended", + "esims", + "total_cents", + "total", + "complete", + "purchasable", + "saves_cents", + "items", + "warnings" + ], + "type": "object" + }, + "type": "array" + }, + "planner_url": { + "description": "The same trip on the SimFuse website, for a person who wants to finish it themselves.", + "type": "string" + }, + "reason": { + "description": "One sentence explaining the recommendation, written to be quoted to the traveller verbatim.", + "type": "string" + }, + "recommendation": { + "description": "Which strategy won: one plan for the whole route, one plan per country, or a mix. Null when nothing we sell covers the trip.", + "enum": [ + "single", + "per_country", + "mixed" + ], + "type": [ + "string", + "null" + ] + }, + "trip": { + "description": "The trip as it was understood, which is worth reading back to the traveller.", + "properties": { + "end": { + "description": "Last day of the trip, YYYY-MM-DD.", + "type": "string" + }, + "span_days": { + "description": "Total days from arrival at the first stop to departure from the last.", + "type": "integer" + }, + "start": { + "description": "First day of the trip, YYYY-MM-DD.", + "type": "string" + }, + "stops": { + "description": "The stops, in travel order, with their dates and data estimates.", + "items": { + "properties": { + "arrive": { + "description": "Arrival date, YYYY-MM-DD.", + "type": "string" + }, + "country": { + "description": "ISO 3166-1 alpha-2 code of the stop.", + "type": "string" + }, + "depart": { + "description": "Departure date, YYYY-MM-DD.", + "type": "string" + }, + "estimated_data": { + "description": "The same estimate written for a person, e.g. \"3.9 GB\".", + "type": "string" + }, + "estimated_mb": { + "description": "Data this stop is estimated to need, in megabytes (1 GB is 1024 MB).", + "type": "integer" + }, + "nights": { + "description": "Days spent at this stop.", + "type": "integer" + }, + "usage": { + "description": "The data appetite used for this stop.", + "enum": [ + "light", + "regular", + "heavy" + ], + "type": "string" + } + }, + "required": [ + "country", + "nights", + "usage", + "arrive", + "depart", + "estimated_mb", + "estimated_data" + ], + "type": "object" + }, + "type": "array" + }, + "token": { + "description": "Compact encoding of the trip, for the planner_url link.", + "type": "string" + } + }, + "required": [ + "token", + "start", + "end", + "span_days", + "stops" + ], + "type": "object" + }, + "warnings": { + "description": "Trip-level caveats: a country SimFuse does not sell, or a gap the recommended option leaves. Say these out loud rather than dropping them.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "contract", + "currency", + "trip", + "recommendation", + "reason", + "options", + "warnings", + "planner_url", + "checkout" + ], + "type": "object" +}
6 tool updates
- First observed
create-checkout-session - First observed
get-plan - First observed
get-plan-coverage - First observed
list-destinations - First observed
list-plans - First observed
plan-trip
Publisher details
- Operator
- Qorinx OÜ · Publisher source
- Operator website
- https://simfuse.app · Publisher source
- Vendor relationship
- First-party · Publisher source
- Documentation
- https://simfuse.app/agent/ · Publisher source
- Trust center
- Not available
- Restrictions
- No setup constraints for reading: destinations, plans, coverage and trip pricing are open and need no account, API key or approval. Buying requires paying for the checkout session over the SimFuse agentic HTTP API with the bearer key that create-checkout-session returns; open payment rails (ACP, UCP, x402) are supported and no partner approval step is involved. No regional limits beyond the countries SimFuse sells eSIMs for.
Related MCP Connectors
Search, recommend & buy travel eSIM data plans for 190+ destinations via AI agents.
Buy and manage travel eSIM data plans in the conversation. Pay by card (Stripe) or USDC over x402.
Estimate mobile-data needs and build a provider-neutral connectivity checklist for any trip.
Travel eSIM catalog: search plans, check availability, and get exact quotes with checkout links.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceLets AI agents search travel eSIM plans by destination, get exact current prices, and hand off to a first-party checkout link without the server ever accepting email or payment credentials.MIT
- -licenseNot gradedqualityBmaintenanceLets AI agents search and buy travel eSIMs from ALT eSIM for 200+ destinations, with Stripe payment links and email delivery of QR codes.-
- AlicenseNot gradedqualityBmaintenancePublic MCP server for a travel-eSIM marketplace: search, recommend and buy data plans for 190+ destinations, returning an attributed checkout link back to simsima.io. Remote Streamable HTTP, no auth.MIT
- AlicenseNot gradedqualityCmaintenanceBrowse, compare, and purchase eSIMs for 190+ countries via AI agents. 12 tools for searching 2,300+ data plans, checking coverage, and buying eSIMs with crypto or card. No account required for browsing.MIT