{
  "info": {
    "_postman_id": "fxport-api-esims-sandbox-v2",
    "name": "FX-Port API - eSIMs (Sandbox)",
    "description": "FX-Port eSIMs API: Postman collection of the documentation at https://fx-port.com/docs (generated 2026-11-01).\n\n**Setup.** Set the collection variable (or an environment) `api_key` to your own key: `fxp_test_...` for the sandbox, `fxp_live_...` for live. The base URL is the same for both, the key decides. The collection holds no key: add yours, and never commit it.\n\n**Names.** Requests use snake_case names. Previous camelCase spellings still work; the response then carries a `warnings` array and `X-FX-Deprecated-Fields` header that name the spelling to use. Add `?naming=snake` to any request for snake_case keys in the response.\n\n**Errors.** Every failure has the same body: `errors[].code`, `errors[].type`, `errors[].message`, and a `request_id` to quote to support.\n\nAPI-facing FX-Port eSIM collection for external/sandbox consumers.\n\nAuth is defined once at the collection root as Bearer {{api_key}}, so every request inherits the same sandbox API key. Only sandbox keys (fxp_test_...) should be used with this collection. External API keys select live or sandbox from the key itself. Requests do not pass an environment parameter.\n\nMultiple suppliers: FX-Port sources eSIM packages from multiple eSIM suppliers, not a single one. Which supplier fulfills a given package is an internal detail; coverage and rates keep improving as FX-Port adds suppliers and as each supplier expands its own network.\n\nPermissions: only 'Create eSIM Order' and 'Create eSIM Topup' require a read+write key. Every other request works with a read-only key.\n\nCommission: agencies are charged a flat 12% commission on top of the B2B price for every package order and topup (0% for corporate/contracted agencies). Kiosk and platform-internal commissions are never included in any response. Each package/topup also reports 'supplier_currency' and 'exchange_rate' (supplier_currency -> your agency currency) so conversion is transparent.\n\nRequired contact details: 'email' and 'phone' are REQUIRED on 'Create eSIM Order' and 'Create eSIM Topup' (not optional) — the supplier emails the QR code and setup instructions directly to that address as soon as the order/topup is confirmed. Only pass the traveler's/client's own contact details — never billing or pricing data.\n\nSupplier continuity: on rare occasions the fulfilling supplier may change the underlying network operator for a country, which can block a topup on an eSIM issued under the previous operator. Always call 'Topup Packages For ICCID' first — if it returns no compatible packages, the eSIM cannot be topped up and a new eSIM order should be placed instead. 'Create eSIM Topup' never debits the agency balance unless the supplier accepts the topup.\n\nChaining: this collection auto-chains requests. 'List Packages' captures 'esim_package_id'. 'Create eSIM Order' captures 'esim_iccid' and 'esim_booking_id'. 'Topup Packages For ICCID' captures 'esim_topup_package_id' from its own response. 'Create eSIM Topup' captures 'esim_topup_booking_id'. Run the folder '02 - Orders And Topups' top-to-bottom to see the full chain.\n\nIncluded API-facing endpoints:\n- eSIM package catalog\n- Compatible devices\n- Orders and topups\n- Usage, booking history, topup history, setup instructions, and installation instructions\n\nIntentionally excluded because they are internal/cache/debug only:\n- POST /api/v1/esims/packages\n- GET /api/v1/esims/packages/status\n- POST /api/v1/esims/packages/refresh\n- GET /api/v1/esims/token/status\n- POST /api/v1/esims/token/refresh\n- GET /api/v1/esims/compatible-devices/status\n- POST /api/v1/esims/compatible-devices/refresh\n- GET /api/v1/esims/bookings/{booking_id}/verify (internal ownership check, no external use case)\n\nQuestions: dev@fx-port.com",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_key}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.fx-port.com"
    },
    {
      "key": "api_key",
      "value": "fxp_test_YOUR_KEY"
    },
    {
      "key": "esim_country_slug",
      "value": "france"
    },
    {
      "key": "esim_filter_type",
      "value": "local"
    },
    {
      "key": "esim_package_id",
      "value": ""
    },
    {
      "key": "esim_topup_package_id",
      "value": ""
    },
    {
      "key": "esim_iccid",
      "value": ""
    },
    {
      "key": "esim_booking_id",
      "value": ""
    },
    {
      "key": "esim_topup_booking_id",
      "value": ""
    },
    {
      "key": "traveler_first_name",
      "value": "Ana"
    },
    {
      "key": "traveler_last_name",
      "value": "Kova"
    },
    {
      "key": "traveler_email",
      "value": "ana.kova@example.com"
    },
    {
      "key": "traveler_phone",
      "value": "+34600123456"
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "const pick = arr => arr[Math.floor(Math.random() * arr.length)];",
          "// Randomize the traveler identity on each run. Intentionally NOT Algeria-only —",
          "// FX-Port serves agencies and travelers worldwide, so examples use a diverse,",
          "// non-region-specific pool of names, countries and phone prefixes.",
          "if (/order|topup/i.test((pm.info && pm.info.requestName) || '') || !pm.collectionVariables.get('traveler_first_name')) {",
          "  const people = [",
          "    { first: 'Ana', last: 'Kova', cc: '+34', dial: () => `6${Math.floor(1e8 + Math.random() * 9e7)}` },",
          "    { first: 'Marco', last: 'Rossi', cc: '+39', dial: () => `3${Math.floor(1e8 + Math.random() * 9e7)}` },",
          "    { first: 'Elena', last: 'Petrova', cc: '+359', dial: () => `8${Math.floor(1e7 + Math.random() * 9e6)}` },",
          "    { first: 'Noah', last: 'Andersson', cc: '+46', dial: () => `70${Math.floor(1e6 + Math.random() * 9e5)}` },",
          "    { first: 'Yuki', last: 'Tanaka', cc: '+81', dial: () => `90${Math.floor(1e7 + Math.random() * 9e6)}` },",
          "    { first: 'Priya', last: 'Nair', cc: '+91', dial: () => `9${Math.floor(1e8 + Math.random() * 9e7)}` },",
          "    { first: 'Kwame', last: 'Mensah', cc: '+233', dial: () => `24${Math.floor(1e6 + Math.random() * 9e5)}` },",
          "    { first: 'Santiago', last: 'Vidal', cc: '+54', dial: () => `11${Math.floor(1e6 + Math.random() * 9e5)}` },",
          "    { first: 'Ingrid', last: 'Haugen', cc: '+47', dial: () => `4${Math.floor(1e7 + Math.random() * 9e6)}` },",
          "    { first: 'Wei', last: 'Zhang', cc: '+65', dial: () => `8${Math.floor(1e6 + Math.random() * 9e5)}` }",
          "  ];",
          "  const p = pick(people);",
          "  pm.collectionVariables.set('traveler_first_name', p.first);",
          "  pm.collectionVariables.set('traveler_last_name', p.last);",
          "  pm.collectionVariables.set('traveler_email', `${p.first.toLowerCase()}.${p.last.toLowerCase()}@example.com`);",
          "  pm.collectionVariables.set('traveler_phone', `${p.cc}${p.dial()}`);",
          "}"
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          "pm.test('HTTP status is successful or accepted', function () {",
          "  pm.expect(pm.response.code).to.be.within(200, 299);",
          "});"
        ]
      }
    }
  ],
  "item": [
    {
      "name": "01 - Catalog",
      "item": [
        {
          "name": "List Packages",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/packages?locale=en",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "packages"
              ],
              "query": [
                {
                  "key": "locale",
                  "value": "en"
                }
              ]
            },
            "description": "Cached package catalog with agency-specific pricing. Read-only.\n\nEach package includes 'price' (B2B price, what is debited from your balance), 'retail_price'/'total_price' (price + 12% agency commission — what you charge the traveler; 0% for corporate/contracted agencies), and 'supplier_currency'/'exchange_rate' showing the currency conversion used. No kiosk or platform-internal commission is ever included.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-packages) · [Package catalog](https://fx-port.com/docs/esims/packages) · [eSIM pricing](https://fx-port.com/docs/esims/pricing)"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "try {",
                  "  const body = pm.response.json();",
                  "  const rows = Array.isArray(body.data) ? body.data : [];",
                  "  if (rows.length && rows[0].id) {",
                  "    pm.collectionVariables.set('esim_package_id', rows[0].id);",
                  "  }",
                  "} catch (error) {}"
                ]
              }
            }
          ]
        },
        {
          "name": "List Packages By Country And Type",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/packages?country={{esim_country_slug}}&filter%5Btype%5D={{esim_filter_type}}&locale=en",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "packages"
              ],
              "query": [
                {
                  "key": "country",
                  "value": "{{esim_country_slug}}"
                },
                {
                  "key": "filter[type]",
                  "value": "{{esim_filter_type}}"
                },
                {
                  "key": "locale",
                  "value": "en"
                }
              ]
            },
            "description": "Package catalog filtered by country slug and package type. `esim_country_slug` / `esim_filter_type` are plain FX-Port catalog filters — which upstream supplier(s) they resolve to is an internal detail.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-packages) · [Package catalog](https://fx-port.com/docs/esims/packages) · [eSIM pricing](https://fx-port.com/docs/esims/pricing)"
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "try {",
                  "  const body = pm.response.json();",
                  "  const rows = Array.isArray(body.data) ? body.data : [];",
                  "  if (rows.length && rows[0].id) {",
                  "    pm.collectionVariables.set('esim_package_id', rows[0].id);",
                  "  }",
                  "} catch (error) {}"
                ]
              }
            }
          ]
        },
        {
          "name": "Compatible Devices",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/compatible-devices",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "compatible-devices"
              ],
              "query": []
            },
            "description": "Cached list of devices known to support eSIM. Read-only. Can briefly return `success: false` with an empty list while the cache is still loading right after a deployment — retry after a few seconds.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-compatible-devices) · [Package catalog](https://fx-port.com/docs/esims/packages)"
          }
        }
      ]
    },
    {
      "name": "02 - Orders And Topups",
      "item": [
        {
          "name": "Create eSIM Order",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"package_id\": \"{{esim_package_id}}\",\n  \"first_name\": \"{{traveler_first_name}}\",\n  \"last_name\": \"{{traveler_last_name}}\",\n  \"email\": \"{{traveler_email}}\",\n  \"phone\": \"{{traveler_phone}}\",\n  \"description\": \"Sandbox eSIM order\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/esims/orders",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "orders"
              ],
              "query": []
            },
            "description": "Create an eSIM order. Requires read_write.\n\nRequired fields: package_id, email, phone. Sending a request without email or phone returns HTTP 400 — they are not optional. The supplier emails the QR code and installation instructions directly to 'email' as soon as the order is confirmed.\n\nTraveler names must use plain Latin (ASCII) letters only — no accents/diacritics and no non-Latin scripts (transliterate to the romanized Latin form). Allowed: A-Z, a-z, spaces, hyphens.\n\nPricing (price + 12% agency commission = total_price) is computed server-side; any pricing fields in the request body are ignored.\n\nRun this request first in this folder — it captures esim_iccid and esim_booking_id for the next two requests.\n\n<!-- fx-generated -->\n**Permission:** Read+Write (the key needs write permission)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/create-esim-order) · [Create an eSIM order](https://fx-port.com/docs/esims/orders) · [eSIM pricing](https://fx-port.com/docs/esims/pricing)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const packageId = pm.collectionVariables.get('esim_package_id');",
                  "if (!packageId) {",
                  "  throw new Error('esim_package_id is required. Run 01 - Catalog / List Packages first, or set esim_package_id manually.');",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "try {",
                  "  const body = pm.response.json();",
                  "  const bookingId = body.booking_id;",
                  "  if (bookingId) pm.collectionVariables.set('esim_booking_id', bookingId);",
                  "  const iccid = body.data && body.data.sim && body.data.sim.iccid;",
                  "  if (iccid) pm.collectionVariables.set('esim_iccid', iccid);",
                  "} catch (error) {}"
                ]
              }
            }
          ]
        },
        {
          "name": "Topup Packages For ICCID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/topup-packages/{{esim_iccid}}?locale=en&force=false",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "topup-packages",
                "{{esim_iccid}}"
              ],
              "query": [
                {
                  "key": "locale",
                  "value": "en"
                },
                {
                  "key": "force",
                  "value": "false"
                }
              ]
            },
            "description": "Get available topup packages for an existing eSIM ICCID. Read-only lookup.\n\nThis calls the fulfilling supplier live for the given ICCID, so the returned list always reflects current availability for that exact SIM — including the rare case where the underlying network operator serving that country has changed since the eSIM was originally issued. An empty result means this eSIM cannot currently be topped up; place a new eSIM order for that traveler instead.\n\nRun this after 'Create eSIM Order' — it captures esim_topup_package_id for 'Create eSIM Topup'.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-topup-packages) · [Top up an eSIM](https://fx-port.com/docs/esims/topups) · [Supplier continuity](https://fx-port.com/docs/esims/supplier-continuity)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const iccid = pm.collectionVariables.get('esim_iccid');",
                  "if (!iccid) {",
                  "  throw new Error('esim_iccid is required. Run Create eSIM Order first, or set esim_iccid manually.');",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "try {",
                  "  const body = pm.response.json();",
                  "  const rows = (body.data && Array.isArray(body.data.data)) ? body.data.data : [];",
                  "  if (rows.length && rows[0].id) {",
                  "    pm.collectionVariables.set('esim_topup_package_id', rows[0].id);",
                  "  } else {",
                  "    console.warn('No topup packages returned for this ICCID — see the Supplier continuity doc before retrying.');",
                  "  }",
                  "} catch (error) {}"
                ]
              }
            }
          ]
        },
        {
          "name": "Create eSIM Topup",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"package_id\": \"{{esim_topup_package_id}}\",\n  \"iccid\": \"{{esim_iccid}}\",\n  \"first_name\": \"{{traveler_first_name}}\",\n  \"last_name\": \"{{traveler_last_name}}\",\n  \"email\": \"{{traveler_email}}\",\n  \"phone\": \"{{traveler_phone}}\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{base_url}}/api/v1/esims/topups",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "topups"
              ],
              "query": []
            },
            "description": "Top up an existing eSIM. Requires read_write.\n\nRequired fields: package_id, iccid, email, phone. Sending a request without email or phone returns HTTP 400 — they are not optional.\n\nAlways run 'Topup Packages For ICCID' first and only pass a package_id it returned — topup availability is fetched live from the supplier per ICCID, so it correctly reflects rare cases where the underlying network operator for that country has changed since the eSIM was issued. If the supplier rejects the topup (e.g. because the original operator no longer serves that ICCID), no balance is debited and no booking is recorded as confirmed.\n\nTopping up adds the new package's data/validity on top of what the eSIM already has rather than replacing it — re-check 'Single eSIM Usage' afterward to see the resulting totals for this specific package.\n\n<!-- fx-generated -->\n**Permission:** Read+Write (the key needs write permission)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/create-esim-topup) · [Top up an eSIM](https://fx-port.com/docs/esims/topups) · [Supplier continuity](https://fx-port.com/docs/esims/supplier-continuity)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const iccid = pm.collectionVariables.get('esim_iccid');",
                  "if (!iccid) {",
                  "  throw new Error('esim_iccid is required. Run Create eSIM Order first, or set esim_iccid manually.');",
                  "}",
                  "const packageId = pm.collectionVariables.get('esim_topup_package_id');",
                  "if (!packageId) {",
                  "  throw new Error('esim_topup_package_id is required. Run Topup Packages For ICCID first, or set esim_topup_package_id manually.');",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "try {",
                  "  const body = pm.response.json();",
                  "  const bookingId = body.booking_id;",
                  "  if (bookingId) pm.collectionVariables.set('esim_topup_booking_id', bookingId);",
                  "} catch (error) {}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "03 - Usage And Bookings",
      "item": [
        {
          "name": "Single eSIM Usage",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/usage/{{esim_iccid}}?force=false",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "usage",
                "{{esim_iccid}}"
              ],
              "query": [
                {
                  "key": "force",
                  "value": "false"
                }
              ]
            },
            "description": "Usage for one ICCID. Read-only.\n\nUsage is cached for up to 15 minutes per ICCID to protect supplier rate limits — it is not guaranteed real-time. Set force=true to bypass the cache when you need the freshest number (e.g. right after a topup), but avoid doing this on every request.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/get-esim-usage) · [eSIM usage](https://fx-port.com/docs/esims/usage)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const iccid = pm.collectionVariables.get('esim_iccid');",
                  "if (!iccid) {",
                  "  throw new Error('esim_iccid is required. Run Create eSIM Order first, or set esim_iccid manually.');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Bulk eSIM Usage",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/usage/bulk?force=false",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "usage",
                "bulk"
              ],
              "query": [
                {
                  "key": "force",
                  "value": "false"
                }
              ]
            },
            "description": "Usage for all eSIMs owned by the authenticated agency. Read-only. Subject to the same 15-minute per-ICCID cache as single usage; per-entry `status` is `success`, `rate_limited`, or `error`.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/get-esim-usage-bulk) · [eSIM usage](https://fx-port.com/docs/esims/usage)"
          }
        },
        {
          "name": "List eSIM Bookings",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/bookings?page=1&limit=50&search=",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "bookings"
              ],
              "query": [
                {
                  "key": "page",
                  "value": "1"
                },
                {
                  "key": "limit",
                  "value": "50"
                },
                {
                  "key": "search",
                  "value": ""
                }
              ]
            },
            "description": "Read-only eSIM booking list for the authenticated agency. Only agency-facing fields are returned — supplier source cost, FX-Port's internal platform margin, and any kiosk/partner-level commission are never included.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-bookings) · [eSIM bookings](https://fx-port.com/docs/esims/bookings)"
          }
        },
        {
          "name": "Check That an eSIM Booking Is Yours",
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('Not a server error', () => pm.expect(pm.response.code).to.be.below(500));"
                ]
              }
            }
          ],
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/bookings/{{booking_id}}/verify",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "bookings",
                "{{booking_id}}",
                "verify"
              ]
            },
            "description": "Tell whether an eSIM booking belongs to your agency, before you build a link or a screen around its `booking_id`.\n\nThe answer is `isOwner` (twin `is_owner`). A booking of another agency and a booking that does not exist answer the same, `false` with status 200, so the call cannot be used to find out which references exist. Only an owner gets `userAgencyId` and `bookingAgencyId`, both your own agency id. The booking must be an eSIM booking of this environment (a sandbox key never sees a live booking).\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/verify-esim-booking) · [eSIM bookings](https://fx-port.com/docs/esims/bookings)"
          },
          "response": []
        }
      ]
    },
    {
      "name": "04 - Instructions And History",
      "item": [
        {
          "name": "Setup Instructions By Booking",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/bookings/{{esim_booking_id}}/setup-instructions",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "bookings",
                "{{esim_booking_id}}",
                "setup-instructions"
              ],
              "query": []
            },
            "description": "Retrieve setup data (QR code, APN, manual/QR install steps) for a booking. Read-only.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/get-esim-setup-instructions) · [Setup and installation instructions](https://fx-port.com/docs/esims/instructions)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const bookingId = pm.collectionVariables.get('esim_booking_id');",
                  "if (!bookingId) {",
                  "  throw new Error('esim_booking_id is required. Run Create eSIM Order first, or set esim_booking_id manually.');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Installation Instructions By ICCID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/instructions/{{esim_iccid}}?locale=en",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "instructions",
                "{{esim_iccid}}"
              ],
              "query": [
                {
                  "key": "locale",
                  "value": "en"
                }
              ]
            },
            "description": "Structured, step-by-step installation instructions per platform for one ICCID. Read-only.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/get-esim-instructions) · [Setup and installation instructions](https://fx-port.com/docs/esims/instructions)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const iccid = pm.collectionVariables.get('esim_iccid');",
                  "if (!iccid) {",
                  "  throw new Error('esim_iccid is required. Run Create eSIM Order first, or set esim_iccid manually.');",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Topup History By ICCID",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{base_url}}/api/v1/esims/bookings/{{esim_iccid}}/topup-history",
              "host": [
                "{{base_url}}"
              ],
              "path": [
                "api",
                "v1",
                "esims",
                "bookings",
                "{{esim_iccid}}",
                "topup-history"
              ],
              "query": []
            },
            "description": "Topup history for an ICCID. Read-only.\n\n<!-- fx-generated -->\n**Permission:** Read (a read-only key is enough)\n\n**Docs:** [API reference](https://fx-port.com/docs/api/list-esim-topup-history) · [eSIM bookings](https://fx-port.com/docs/esims/bookings)"
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const iccid = pm.collectionVariables.get('esim_iccid');",
                  "if (!iccid) {",
                  "  throw new Error('esim_iccid is required. Run Create eSIM Order first, or set esim_iccid manually.');",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
