{
  "openapi": "3.1.0",
  "info": {
    "title": "SimWay Partner API",
    "version": "v1",
    "summary": "Buy eSIM data plans programmatically at a partner price and resell them.",
    "description": "Prepaid, server-to-server REST API over the SimWay eSIM catalogue.\n\nGenerated from the published reference at https://simway.pro/partners/docs, not introspected from the running service — so it agrees with the human documentation by construction and is exactly as correct as that documentation is. Response bodies are described by example rather than by exhaustive schema; treat them as illustrative, not as a validation contract.\n\nNotable behaviours a generated client must account for:\n- No CORS headers are emitted at all. This API cannot be called from a browser.\n- Unknown query parameters and unknown body fields are refused with 400, not ignored.\n- POST /orders requires an Idempotency-Key header, and some refusals bind that key permanently. See https://simway.pro/partners/docs/idempotency.\n- POST /orders answers 202 on first delivery and 200 on a replay. Both are success.\n- There are no webhooks. Poll GET /orders/{id} while poll_after_ms is not null.\n- metadata is echoed verbatim and must serialise to at most 4096 bytes.\n\nReference last updated 2026-08-18.",
    "termsOfService": "https://simway.pro/terms",
    "contact": {
      "name": "SimWay partner support",
      "email": "support@simway.pro",
      "url": "https://simway.pro/partners"
    }
  },
  "externalDocs": {
    "description": "Full reference",
    "url": "https://simway.pro/partners/docs"
  },
  "servers": [
    {
      "url": "https://api.simway.pro/partner/v1",
      "description": "Production. Live and sandbox share it; the key decides the mode."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Account",
      "description": "Health, identity, balance and the statement.",
      "externalDocs": {
        "url": "https://simway.pro/partners/docs/account"
      }
    },
    {
      "name": "Catalogue",
      "description": "Plans, destinations and the price dry run.",
      "externalDocs": {
        "url": "https://simway.pro/partners/docs/catalogue"
      }
    },
    {
      "name": "Orders",
      "description": "Buying, and the lifecycle of what you bought.",
      "externalDocs": {
        "url": "https://simway.pro/partners/docs/orders"
      }
    },
    {
      "name": "eSIMs",
      "description": "Profiles, install payloads and usage.",
      "externalDocs": {
        "url": "https://simway.pro/partners/docs/esims"
      }
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A key of the form simway_sk_live_<43 base62> or simway_sk_test_<43 base62>. Mode is a property of the key; no request field can change it."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "type",
              "code",
              "message",
              "doc_url",
              "request_id"
            ],
            "properties": {
              "type": {
                "type": "string",
                "description": "Coarse family, for one branch per kind."
              },
              "code": {
                "type": "string",
                "description": "Stable forever. The value to branch on.",
                "enum": [
                  "request.invalid",
                  "plan.inactive",
                  "auth.missing",
                  "auth.invalid_key",
                  "auth.key_expired",
                  "balance.insufficient",
                  "auth.ip_not_allowed",
                  "partner.not_live",
                  "partner.suspended",
                  "partner.closed",
                  "forbidden",
                  "plan.not_found",
                  "order.not_found",
                  "esim.not_found",
                  "not_found",
                  "idempotency.key_reused",
                  "order.in_progress",
                  "order.not_cancellable",
                  "conflict",
                  "plan.unavailable",
                  "rate_limit.exceeded",
                  "internal_error",
                  "supplier_error",
                  "service_unavailable"
                ]
              },
              "message": {
                "type": "string",
                "description": "Prose for a human. MAY CHANGE WITHOUT NOTICE — never parse it."
              },
              "doc_url": {
                "type": "string",
                "format": "uri"
              },
              "request_id": {
                "type": "string"
              },
              "param": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The offending field, where there was one."
              }
            },
            "additionalProperties": true
          }
        }
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Liveness, without a credential.",
        "description": "Service health\n\nThe only route on this API that takes no key and is subject to no rate limit. It exists so your monitoring can watch us without you embedding a credential in a monitoring system.\nIt answers 503 — not 200 with a sad body — when the database probe fails or takes longer than two seconds, so an uptime checker configured with nothing but a URL still does the right thing.\n\nNotes:\n- No `object` field and no `X-RateLimit-*` headers: the rate-limit guard never runs on this route.",
        "tags": [
          "Account"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "status": "ok",
                  "uptime_seconds": 41233,
                  "database": "ok"
                }
              }
            }
          },
          "503": {
            "description": "Database unreachable or slow",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "status": "degraded",
                  "uptime_seconds": 41233,
                  "database": "down"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Who this credential belongs to, and what it may do.",
        "description": "Your account and this key\n\nRead fresh from the database on every call, never from the cached principal — so it is the authoritative answer to “which key is this and is it live”.\n`mode` is a property of the KEY, never of the account and never of the request. No header, query flag or body field can change it.\n`rate_limits` is computed live from your band. It is the machine-readable form of the rate-limit page and it moves with your tier without us redeploying anything, so read it rather than hard-coding the table.\n\nNotes:\n- `key` is null — rather than the whole call failing — if the key row cannot be read. The partner is still answered.\n- `status` is the account’s (`sandbox`, `pending`, `live`, `suspended`, `closed`); `mode` is the key’s. They are different questions and they are allowed to disagree: a sandbox key on a live account reports `status: \"live\", mode: \"sandbox\"`.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "The account",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "partner",
                  "id": "pt_c8k2m4p9x1v7b3n6q0w5t2r8",
                  "name": "Northwind Travel",
                  "slug": "northwind-travel",
                  "status": "live",
                  "mode": "live",
                  "tier": "silver",
                  "key": {
                    "id": "pk_c4h9j2n7x5v1b8m3q6w0t4r2",
                    "label": "production-checkout",
                    "last4": "aB3x",
                    "mode": "live",
                    "expires_at": null,
                    "created_at": "2026-07-02T11:20:41Z"
                  },
                  "rate_limits": {
                    "read": {
                      "limit": 20,
                      "window_seconds": 1
                    },
                    "write": {
                      "limit": 25,
                      "window_seconds": 5
                    },
                    "supplier": {
                      "limit": 2,
                      "window_seconds": 1
                    },
                    "catalogue": {
                      "limit": 120,
                      "window_seconds": 60
                    }
                  },
                  "created_at": "2026-06-18T08:02:15Z"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Prepaid funds, and the headline discount they buy.",
        "description": "Balance\n\nDeliberately un-cached: read fresh on every call, because it is the number a checkout decides on.\nA sandbox key reports the sandbox float instead. Same field, same shape — only the money is imaginary.\n\nNotes:\n- `discount_bps` here is the HEADLINE rate — your tier, or the override that supersedes it. The per-plan figure in the catalogue can be lower. They are allowed to differ and the difference is the point; see the pricing page.\n- `currency` is a pinned constant. It is never derived from a request and there is no way to be billed in anything else.",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "Balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "balance",
                  "balance_cents": 48309,
                  "currency": "USD",
                  "tier": "silver",
                  "discount_bps": 1200,
                  "low_balance_threshold_cents": 2000,
                  "mode": "live"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/ledger": {
      "get": {
        "operationId": "getLedger",
        "summary": "Every movement of money, newest first.",
        "description": "Statement\n\nThe statement is the books. `seq` and `balance_after_cents` are allocated by the same statement that moved the money, so any window reconciles by construction: the sum of `amount_cents` over a page equals the difference of the balances at its ends.\nA sandbox key always receives an empty page. Sandbox spend moves the sandbox float and writes no statement row at all, because the ledger has no mode column and a sandbox row would break the invariant an hourly job checks. The practical consequence is worth planning for: you cannot exercise statement-rendering code in sandbox.\n\nNotes:\n- Lists answer `{ \"data\": [...], \"has_more\": bool, \"next_cursor\": string|null }`. There is no total count anywhere on this API, deliberately — counting costs a second scan of everything the filter matched, and `has_more` answers the only question a paging client has.\n- Ordered by `seq` descending. A refund appears as its own row, never as an edit to the purchase.",
        "tags": [
          "Account"
        ],
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "description": "Filter by movement type.",
            "schema": {
              "type": "string",
              "enum": [
                "deposit",
                "purchase",
                "refund",
                "adjustment",
                "payout",
                "chargeback"
              ]
            },
            "example": "purchase"
          },
          {
            "name": "created_after",
            "in": "query",
            "required": false,
            "description": "INCLUSIVE — `created_at >= value`. Note this differs from /orders and /esims, where the same parameter is exclusive.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_before",
            "in": "query",
            "required": false,
            "description": "Exclusive — `created_at < value`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. 1–200 Default: 50.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque. Pass back `next_cursor` from the previous page, or omit it to start again. A malformed cursor is a 400 naming `cursor`, never a silent first page. ≤ 512 characters",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "object": "ledger_entry",
                      "id": "led_c9x4k7n2v5b1m8q3w0t6r4j9",
                      "seq": 4412,
                      "kind": "purchase",
                      "amount_cents": -5256,
                      "balance_after_cents": 43053,
                      "description": "Example Republic 5 GB / 30 days x3",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "deposit_id": null,
                      "created_at": "2026-08-17T09:14:22Z"
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "eyJzIjo0NDEyfQ"
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/deposits": {
      "post": {
        "operationId": "postDeposits",
        "summary": "Mint a crypto invoice. It credits the float when it settles.",
        "description": "Open a deposit\n\nThe only route that makes the balance go UP, and the only one whose answer is not something that has happened. It creates an INVOICE: the deposit is `pending`, your float is untouched, and a deposit you open and walk away from has cost you a row and nothing else. The credit happens when the crypto settles and the provider calls us back, and only then.\nIt answers 201, not the orders endpoint's 202. A 202 there means \"we have your money and are provisioning\". Here nothing is in flight and nothing has been accepted — a resource was created and the money arrives if and when you pay it.\nWhole dollars only, $100 to $10,000. The ceiling bounds one fat-finger, not how much float you may hold: two invoices are always available, and a bank transfer has a person on it and no ceiling at all.\nCrypto, not cards. That is a decision rather than a gap, and the reason is on the page that renders this endpoint.\n\nNotes:\n- NO `Idempotency-Key`, and its absence is deliberate rather than an oversight. A repeated POST mints a second invoice, which costs a row and nothing else — an unpaid invoice is not a charge, and two invoices credit twice only if you pay both, at which point you have sent twice the money and both credits are correct. What the key buys on `POST /orders` is protection against a retry charging twice; there is no charge here to repeat.\n- A SANDBOX key is refused with `403 forbidden` carrying `mode: \"sandbox\"`. Sandbox spending comes from the play-money float, which is refilled on request, so a sandbox key reaching this rail would be sending real cryptocurrency to exercise a code path.\n- OVERPAYMENT IS CREDITED IN FULL. If $500 of crypto settles as slightly more in USD, the whole of it lands on your float — we do not keep the surplus and we do not cap the credit at the invoice. `credited_cents` greater than `requested_cents` is a normal response and not an error; do not reconcile against the invoiced figure.\n- UNDERPAYMENT IS CREDITED AT WHAT ARRIVED. A short settlement credits the short amount rather than nothing and rather than the invoice. While the provider still considers the invoice open and payable, nothing at all is credited until the amount is final — so a deposit can sit `pending` after a partial payment. A settlement that reports a readable zero credits nothing and raises a review with us.\n- A REFUND BEFORE THE CREDIT IS TERMINAL. The deposit closes as `refunded` and nothing will ever re-drive it — unlike `cancelled`, which stays claimable because crypto broadcast before an invoice lapsed and confirmed after it is ordinary. A REFUND AFTER THE CREDIT DOES NOT TAKE THE FLOAT BACK: the money returns to the payer and the float stays where it is, possibly already spent on profiles. It is reconciled by a person, and it is the one behaviour on this rail worth knowing before it happens to you.\n- An account CLOSED between minting the invoice and paying it is never credited. The deposit stays claimable, nothing lands, and a person has to decide between returning the money and re-opening the account. Do not open an invoice you are not about to pay.\n- `payment_url` is a page hosted by our payment provider. The host is not part of this contract, it is not stable, and it must not be pattern-matched — send the customer, or yourself, to whatever the field says.",
        "tags": [
          "Account"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "amount_cents": {
                    "type": "integer",
                    "description": "Integer US cents, and a whole number of dollars — a multiple of 100. It is the amount you are choosing to send, not an amount you are reporting, and a round figure is what makes an invoice, a bank statement and a ledger row line up when somebody reconciles them by eye later. What actually arrives is credited to the cent regardless. $100–$10,000, in multiples of 100 cents"
                  }
                },
                "required": [
                  "amount_cents"
                ]
              },
              "example": {
                "amount_cents": 50000
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invoice created — nothing has moved yet",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "deposit",
                  "id": "dep_c5n2k8x7v3b9m1q4w6t0r7j2",
                  "status": "pending",
                  "method": "crypto",
                  "requested_cents": 50000,
                  "credited_cents": null,
                  "currency": "USD",
                  "reference": null,
                  "ledger_entry_id": null,
                  "payment_url": "https://pay.example.com/invoice/9f2c41b8e7d54a0c",
                  "expires_at": "2026-08-17T10:14:22Z",
                  "created_at": "2026-08-17T09:14:22Z",
                  "credited_at": null
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, forbidden, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "service_unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "write"
      },
      "get": {
        "operationId": "getDeposits",
        "summary": "Your funding history, newest first — and where to pay what is open.",
        "description": "List deposits\n\nEvery deposit on the account, whichever rail it came in on: the crypto invoices this API mints, and the bank transfers a person records for you. `method` tells them apart.\nThe invoice link is on the list as well as on the single read, because \"which of my deposits is still waiting to be paid, and where do I pay it\" is the question this endpoint exists to answer.\nA SANDBOX key always receives an empty page. That is consistent rather than missing: the sandbox float is not money, so it writes no deposit and no statement row — the same answer `GET /ledger` gives, for the same reason.\n\nNotes:\n- Lists answer `{ \"data\": [...], \"has_more\": bool, \"next_cursor\": string|null }`. There is no total count anywhere on this API, deliberately — counting costs a second scan of everything the filter matched, and `has_more` answers the only question a paging client has.\n- `status` outside the published set is a 400 naming `status`, not an empty page. The five are `pending`, `credited`, `cancelled`, `refunded`, `reversed`.\n- `credited_cents` is null until the money lands, and then it is what ARRIVED — which can be more or less than `requested_cents`. The two fields are separate precisely because that difference is what a finance person spends the day chasing.\n- `ledger_entry_id` is the statement row the credit wrote. It is null on anything not yet credited, and it is the join between this list and `GET /ledger`.\n- `reference` is the OTHER side’s identifier, never yours — there is no field on this rail for one of your own. On a crypto deposit it is the payment provider’s id for the invoice, written when the callback confirms the payment, which happens BEFORE the float moves and before the status leaves `pending`. So a `pending` deposit may already carry one — that is the window between a confirmed payment and a settled credit, and the reconciler can hold it open for minutes. **Never read `reference` as a proxy for credited**: a row with a reference and `status: \"pending\"` is money we have seen and not yet placed on your float, and shipping against it ships against money you cannot spend. `credited_cents` and `status` are the only answers to \"may I spend this\". A crypto row is also allowed to reach `credited` with no reference at all, if the confirming callback carried no id of its own. On a wire it is what an operator copied off the bank statement. It is unique per account, which is what makes crediting the same payment twice impossible.\n- `method` is the discriminator and the two shapes differ in three fields, not one: `crypto` carries a `payment_url` and an `expires_at` and reaches `credited` through a callback; `wire` is recorded by a person already credited, so it has no invoice to pay, nothing to lapse, and `requested_cents` equal to `credited_cents` by construction. Branch on `method`, never on whether `payment_url` happens to be null.",
        "tags": [
          "Account"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by state. `refunded` is terminal. `cancelled` is NOT: an invoice that lapsed is still claimable, because crypto broadcast before it lapsed and confirmed after it is ordinary.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "credited",
                "cancelled",
                "refunded",
                "reversed"
              ]
            },
            "example": "credited"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. 1–200 Default: 50.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque. Pass back `next_cursor` from the previous page, or omit it to start again. A malformed cursor is a 400 naming `cursor`, never a silent first page. ≤ 512 characters",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page — an open invoice, an overpaid credit, and a bank transfer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "object": "deposit",
                      "id": "dep_c5n2k8x7v3b9m1q4w6t0r7j2",
                      "status": "pending",
                      "method": "crypto",
                      "requested_cents": 50000,
                      "credited_cents": null,
                      "currency": "USD",
                      "reference": null,
                      "ledger_entry_id": null,
                      "payment_url": "https://pay.example.com/invoice/9f2c41b8e7d54a0c",
                      "expires_at": "2026-08-17T10:14:22Z",
                      "created_at": "2026-08-17T09:14:22Z",
                      "credited_at": null
                    },
                    {
                      "object": "deposit",
                      "id": "dep_c2v8k4n7x1b5m9q3w6t0r8j4",
                      "status": "credited",
                      "method": "crypto",
                      "requested_cents": 50000,
                      "credited_cents": 50200,
                      "currency": "USD",
                      "reference": "5b0e7a94-2d13-4f8c-9a26-0c7e1f45b382",
                      "ledger_entry_id": "led_c9x4k7n2v5b1m8q3w0t6r4j9",
                      "payment_url": "https://pay.example.com/invoice/4c1f8a26d90b7e35",
                      "expires_at": "2026-08-11T13:40:08Z",
                      "created_at": "2026-08-11T12:40:08Z",
                      "credited_at": "2026-08-11T12:52:44Z"
                    },
                    {
                      "object": "deposit",
                      "id": "dep_c7b3k1n9x4v6m2q8w5t0r3j6",
                      "status": "credited",
                      "method": "wire",
                      "requested_cents": 3000000,
                      "credited_cents": 3000000,
                      "currency": "USD",
                      "reference": "FT-XX-9042175538",
                      "ledger_entry_id": "led_c4k8n1x6v3b7m2q9w5t0r8j3",
                      "payment_url": null,
                      "expires_at": null,
                      "created_at": "2026-08-04T15:31:12Z",
                      "credited_at": "2026-08-04T15:31:12Z"
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "eyJjIjoiMjAyNi0wOC0wNFQxNTozMToxMi4wMDBaIiwiaSI6ImM3YjNrMW45eDR2Nm0ycTh3NXQwcjNqNiJ9"
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/deposits/{id}": {
      "get": {
        "operationId": "getDeposit",
        "summary": "One deposit, including where to pay it.",
        "description": "Get one deposit\n\nThe answer to \"I lost the invoice link\". Same shape as a row in the list, always scoped to your own account.\nA SANDBOX key never resolves a deposit here: the sandbox writes none, so every well-formed `dep_` id is `404 not_found`. It is not \"404 whatever you send\" — the id is parsed first, so a wrong-kind id is the 400 described below and `mode` is never reached.\n\nNotes:\n- An invoice is payable for 60 minutes on the provider side — we pass no lifetime, so that is their default. `expires_at` is when it lapses; after that the deposit becomes `cancelled`, which is still claimable, so crypto broadcast inside the window and confirmed after it still credits. Open another invoice rather than waiting on a lapsed one.",
        "tags": [
          "Account"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Must begin `dep_`. A wrong-kind id is a 400 naming `id`, not a 404.",
            "schema": {
              "type": "string"
            },
            "example": "dep_c5n2k8x7v3b9m1q4w6t0r7j2"
          }
        ],
        "responses": {
          "200": {
            "description": "An invoice waiting to be paid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "deposit",
                  "id": "dep_c5n2k8x7v3b9m1q4w6t0r7j2",
                  "status": "pending",
                  "method": "crypto",
                  "requested_cents": 50000,
                  "credited_cents": null,
                  "currency": "USD",
                  "reference": null,
                  "ledger_entry_id": null,
                  "payment_url": "https://pay.example.com/invoice/9f2c41b8e7d54a0c",
                  "expires_at": "2026-08-17T10:14:22Z",
                  "created_at": "2026-08-17T09:14:22Z",
                  "credited_at": null
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/plans": {
      "get": {
        "operationId": "getPlans",
        "summary": "The whole catalogue, priced for you.",
        "description": "List plans\n\nThis is the only endpoint in the `catalogue` rate class, and it is the reason that class exists: one request is the entire price list computed for one buyer.\nOrdering is stable across pages — country code, then data, then duration, then id — and the cursor is a keyset over exactly that tuple, so a full walk sees every row once even while the catalogue sync rewrites rows underneath it.\n\nNotes:\n- Lists answer `{ \"data\": [...], \"has_more\": bool, \"next_cursor\": string|null }`. There is no total count anywhere on this API, deliberately — counting costs a second scan of everything the filter matched, and `has_more` answers the only question a paging client has.\n- A deactivated plan DROPS OUT of this list rather than arriving with `available: false`. So `updated_since` will never tell you about a deletion, and a mirror still needs an occasional full pass. `GET /plans/{id}` is where a delisting is visible.\n- `networks` names the operators the plan actually roams onto, from the supplier’s network list — never from the `speed` field, which uses a different vocabulary and disagrees with it on more than half the catalogue. `null` means we hold no operator data for that plan, not that it roams onto nothing.\n- `requires_kyc` is null on every row today, and null means UNKNOWN. It is published as unknown on purpose rather than as `false`.\n- `min_resale_price_cents` is null on every row: a forward-compatible slot, not a rule we impose today. There is no minimum resale price.\n- An unknown query parameter is a 400. `?contry=JP` fails loudly rather than returning the whole catalogue.",
        "tags": [
          "Catalogue"
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "ISO 3166-1 alpha-2, case-insensitive. The examples here use `ZZ`, a code ISO reserves for private use so that nothing in this reference can be mistaken for a claim about a real destination — send a real one (`JP`, `TR`) against your own key. at most 2 characters — a 3-letter code is a 400, but a 1-letter code validates and returns an empty page rather than an error",
            "schema": {
              "type": "string"
            },
            "example": "ZZ"
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Matches either a regional-bundle slug or a country’s region. ≤ 64 characters",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Bundle shape.",
            "schema": {
              "type": "string",
              "enum": [
                "fixed",
                "daily"
              ]
            }
          },
          {
            "name": "min_days",
            "in": "query",
            "required": false,
            "description": "Inclusive lower bound on `duration_days`. ≥ 1",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_days",
            "in": "query",
            "required": false,
            "description": "Inclusive upper bound on `duration_days`. ≥ 1",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "min_data_mb",
            "in": "query",
            "required": false,
            "description": "Inclusive lower bound on `data_amount_mb`. ≥ 0",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "max_data_mb",
            "in": "query",
            "required": false,
            "description": "Inclusive upper bound on `data_amount_mb`. ≥ 0",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "unlimited",
            "in": "query",
            "required": false,
            "description": "The strings only. `?unlimited=yes` is a 400, deliberately.",
            "schema": {
              "type": "string",
              "enum": [
                "true",
                "false"
              ]
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "required": false,
            "description": "EXCLUSIVE — `>`. The incremental-sync parameter.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. 1–200 Default: 50.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque. Pass back `next_cursor` from the previous page, or omit it to start again. A malformed cursor is a 400 naming `cursor`, never a silent first page. ≤ 512 characters",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of plans",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "object": "plan",
                      "id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "name": "Example Republic 5 GB / 30 days",
                      "country_code": "ZZ",
                      "region": null,
                      "global": false,
                      "plan_type": "fixed",
                      "data_amount_mb": 5120,
                      "daily_allowance_mb": null,
                      "fup_speed": null,
                      "unlimited": false,
                      "duration_days": 30,
                      "voice_minutes": null,
                      "sms_count": null,
                      "coverage_types": [
                        "data"
                      ],
                      "speed": "4G/LTE",
                      "networks": [
                        "Example Mobile",
                        "Example Telecom"
                      ],
                      "requires_kyc": null,
                      "list_price_cents": 1990,
                      "your_price_cents": 1752,
                      "discount_bps": 1200,
                      "price_source": "tier:silver",
                      "tier": "silver",
                      "min_resale_price_cents": null,
                      "available": true
                    }
                  ],
                  "has_more": true,
                  "next_cursor": "eyJjIjoiWloiLCJkIjo1MTIwLCJ0IjozMCwiaSI6ImMzbjhrNXgydjliNG03cTF3NnQzcjBqNSJ9"
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "catalogue"
      }
    },
    "/plans/{id}": {
      "get": {
        "operationId": "getPlan",
        "summary": "Resolve a stored plan id, including a delisted one.",
        "description": "Get one plan\n\nThe important divergence from the list: an INACTIVE plan is returned here with `available: false` rather than 404’d. That is what lets a mirror resolve an id it stored last week and propagate the delisting to its own catalogue.\nA plan that never existed, that is a sandbox fixture seen by a live key, or that sits in a withdrawn destination is genuinely a 404.",
        "tags": [
          "Catalogue"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Must begin `pl_`. A wrong-kind id is a 400 naming `id`, not a 404.",
            "schema": {
              "type": "string"
            },
            "example": "pl_c3n8k5x2v9b4m7q1w6t3r0j5"
          }
        ],
        "responses": {
          "200": {
            "description": "A delisted plan",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "plan",
                  "id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "name": "Example Republic 5 GB / 30 days",
                  "country_code": "ZZ",
                  "region": null,
                  "global": false,
                  "plan_type": "fixed",
                  "data_amount_mb": 5120,
                  "daily_allowance_mb": null,
                  "fup_speed": null,
                  "unlimited": false,
                  "duration_days": 30,
                  "voice_minutes": null,
                  "sms_count": null,
                  "coverage_types": [
                    "data"
                  ],
                  "speed": "4G/LTE",
                  "networks": [
                    "Example Mobile",
                    "Example Telecom"
                  ],
                  "requires_kyc": null,
                  "list_price_cents": 1990,
                  "your_price_cents": 1752,
                  "discount_bps": 1200,
                  "price_source": "tier:silver",
                  "tier": "silver",
                  "min_resale_price_cents": null,
                  "available": false
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "plan.not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/plans/{id}/price": {
      "get": {
        "operationId": "getPlanPrice",
        "summary": "What an order would cost, and whether it would clear.",
        "description": "Price a purchase (dry run)\n\nDeducts nothing, provisions nothing, reserves nothing. Call it before every order and you never spend an idempotency key on a 402 — which matters here more than on most APIs, because a 402 binds its key permanently.\nThe quantity cap matches the order endpoint exactly, so a basket that prices cannot fail to order for want of a bigger cap.\n\nNotes:\n- This is the one priced object on the API with NO `object` field. If your deserialiser keys on it, special-case this response.\n- A quote is not a reservation and not a price lock. It is what the catalogue says right now. The price that binds is the one snapshotted onto the order when it is accepted.\n- If the plan is not available, this raises 422 with a deliberately vague message, because the dry run holds only the boolean and not the reason. Place the order to be told which reason.",
        "tags": [
          "Catalogue"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Must begin `pl_`.",
            "schema": {
              "type": "string"
            },
            "example": "pl_c3n8k5x2v9b4m7q1w6t3r0j5"
          },
          {
            "name": "quantity",
            "in": "query",
            "required": false,
            "description": "How many profiles. 1–50 Default: 1.",
            "schema": {
              "type": "integer"
            },
            "example": 3
          }
        ],
        "responses": {
          "200": {
            "description": "A quote",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "quantity": 3,
                  "unit_price_cents": 1752,
                  "total_cents": 5256,
                  "list_unit_cents": 1990,
                  "discount_bps": 1200,
                  "price_source": "tier:silver",
                  "tier": "silver",
                  "balance_cents": 48309,
                  "sufficient_balance": true,
                  "mode": "live"
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "plan.not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "plan.unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/destinations": {
      "get": {
        "operationId": "getDestinations",
        "summary": "Every country you can sell, with your own entry price.",
        "description": "List destinations\n\nBuilt for the page a partner puts in front of their own customers: a country, a plan count, and a price to say “from”.\n`from_price_cents` is the cheapest price YOU can buy in that destination, not the cheapest list price. The two differ, so quoting the list minimum on your own site would advertise a margin you do not have.\n\nNotes:\n- It uses the list envelope but never pages: `has_more` is always false and `next_cursor` always null.\n- Items have no `object` field.\n- Regional and global bundles carry no country code and are excluded from this endpoint entirely. Use `GET /plans?region=` for those.\n- Plans that cannot be sold to you are excluded from both the count and the from-price, so the two agree with what `GET /plans?country=` will actually return.\n- Cached for ten minutes, keyed on your rate rather than on your account — so every partner on the same rate shares one entry and one of you warms it for all.",
        "tags": [
          "Catalogue"
        ],
        "responses": {
          "200": {
            "description": "Destinations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "code": "ZZ",
                      "name": "Example Republic",
                      "region": "asia",
                      "plan_count": 34,
                      "from_price_cents": 1752
                    },
                    {
                      "code": "XA",
                      "name": "Example Islands",
                      "region": "europe",
                      "plan_count": 28,
                      "from_price_cents": 872
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/orders": {
      "post": {
        "operationId": "postOrders",
        "summary": "The only endpoint that spends money. Always answers 202.",
        "description": "Place an order\n\nThe money moves synchronously and the profiles do not. By the time you hold the 202, your balance has been debited, the statement row exists and the child orders have been created; provisioning then runs detached and you poll for it.\nIt answers 202 rather than waiting because one provisioning run can take up to 92 seconds, a quantity-N order drives its units one at a time, and a typical HTTP client gives up at 30 seconds and retries. A retry on a purchase is a double charge. Asynchronous is not a design flourish here; it is the only shape that is safe.\n`Idempotency-Key` is required. There is no way to place an order without one.\n\nNotes:\n- The 202 body is ALWAYS `status: \"processing\"`, `esims: []`, `completed_at: null` — even when provisioning finishes five seconds later. It is a receipt for the money, not the final state.\n- A replay is 200, not 202, and carries `Idempotency-Replayed: true`. That asymmetry is the whole point: a client that retried on a timeout can tell “we accepted this” from “you have seen this before”.\n- `discount_bps` on an order is recomputed from the two stored money columns, so it can read one to a few basis points below the catalogue’s figure for the same plan. That gap is the half-cent the price rounding removed, and understating is the safe direction.\n- Never retry a 202. The order is durable: a detached run, a 120-second drain on shutdown, and a per-minute reconciler that re-drives anything stranded.",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Unique to this order — a UUID, or your own booking id. Send the SAME value if you retry. Scoped per partner and spanning both modes. 16–255 characters after trimming",
            "schema": {
              "type": "string"
            },
            "example": "8f3c2a1e-7b64-4d59-9e02-1c5a7f8b3d20"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "plan_id": {
                    "type": "string",
                    "description": "Must begin `pl_`. ≤ 64 characters"
                  },
                  "quantity": {
                    "type": "integer",
                    "description": "How many profiles. Each is provisioned individually. 1–50 Default: 1."
                  },
                  "reference": {
                    "type": "string",
                    "description": "Your own identifier. Never parsed by us, echoed on every read, and exact-match filterable on the order list. Trimmed; empty becomes null. ≤ 255 characters"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Your own blob, echoed back verbatim — its inner keys are NOT converted to snake_case like the rest of the response. Must be a JSON object; an array or a bare string is a 400. serialises to ≤ 4096 bytes of UTF-8"
                  }
                },
                "required": [
                  "plan_id"
                ]
              },
              "example": {
                "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                "quantity": 3,
                "reference": "BK-99182",
                "metadata": {
                  "bookingId": "BK-99182",
                  "travellerEmail": "ada@example.com"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replay — you have sent this before",
            "headers": {
              "Idempotency-Replayed": {
                "description": "`true`. Set on replays only.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "order",
                  "id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                  "mode": "live",
                  "status": "completed",
                  "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "quantity": 3,
                  "unit_price_cents": 1752,
                  "total_cents": 5256,
                  "list_unit_cents": 1990,
                  "discount_bps": 1195,
                  "price_source": "tier:silver",
                  "tier": "silver",
                  "reference": "BK-99182",
                  "metadata": {
                    "bookingId": "BK-99182",
                    "travellerEmail": "ada@example.com"
                  },
                  "esims": [
                    {
                      "object": "esim",
                      "iccid": "8944500102030405062",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "provisioned",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-1A9QX-88ZLM",
                        "activation_code": "LPA:1$rsp.example.com$K2-1A9QX-88ZLM",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-1A9QX-88ZLM"
                      },
                      "usage": {
                        "data_used_bytes": 0,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": null,
                      "expires_at": "2026-09-17T06:41:03Z"
                    },
                    {
                      "object": "esim",
                      "iccid": "8944500102030405070",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "provisioned",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-7F4RD-31TVP",
                        "activation_code": "LPA:1$rsp.example.com$K2-7F4RD-31TVP",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-7F4RD-31TVP"
                      },
                      "usage": {
                        "data_used_bytes": 0,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": null,
                      "expires_at": "2026-09-17T06:41:03Z"
                    },
                    {
                      "object": "esim",
                      "iccid": "8944500102030405088",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "provisioned",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-5B2WH-96YKS",
                        "activation_code": "LPA:1$rsp.example.com$K2-5B2WH-96YKS",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-5B2WH-96YKS"
                      },
                      "usage": {
                        "data_used_bytes": 0,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": null,
                      "expires_at": "2026-09-17T06:41:03Z"
                    }
                  ],
                  "failure_code": null,
                  "failure_message": null,
                  "balance_after_cents": 43053,
                  "poll_after_ms": null,
                  "created_at": "2026-08-17T09:14:22Z",
                  "completed_at": "2026-08-17T09:14:27Z"
                }
              }
            }
          },
          "202": {
            "description": "Accepted — money moved, profiles pending",
            "headers": {
              "X-Request-Id": {
                "description": "Quote it to support. Present on every response, including 401s.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "order",
                  "id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                  "mode": "live",
                  "status": "processing",
                  "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "quantity": 3,
                  "unit_price_cents": 1752,
                  "total_cents": 5256,
                  "list_unit_cents": 1990,
                  "discount_bps": 1195,
                  "price_source": "tier:silver",
                  "tier": "silver",
                  "reference": "BK-99182",
                  "metadata": {
                    "bookingId": "BK-99182",
                    "travellerEmail": "ada@example.com"
                  },
                  "esims": [],
                  "failure_code": null,
                  "failure_message": null,
                  "balance_after_cents": 43053,
                  "poll_after_ms": 2000,
                  "created_at": "2026-08-17T09:14:22Z",
                  "completed_at": null
                }
              }
            }
          },
          "400": {
            "description": "request.invalid, plan.inactive",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "balance.insufficient",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "plan.not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "idempotency.key_reused",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "plan.unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "internal_error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "write"
      },
      "get": {
        "operationId": "getOrders",
        "summary": "Your orders, newest first, scoped to this key’s mode.",
        "description": "List orders\n\nScoped to your account AND the mode of the key you sent. A live key never sees sandbox orders and vice versa.\n\nNotes:\n- Lists answer `{ \"data\": [...], \"has_more\": bool, \"next_cursor\": string|null }`. There is no total count anywhere on this API, deliberately — counting costs a second scan of everything the filter matched, and `has_more` answers the only question a paging client has.\n- `cancelled` is accepted as a filter but nothing in the system ever writes it. There is no cancellation endpoint.\n- `metadata` defaults to `{}` on the wire, never null.",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by state.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "processing",
                "completed",
                "partial",
                "failed",
                "cancelled"
              ]
            },
            "example": "processing"
          },
          {
            "name": "created_after",
            "in": "query",
            "required": false,
            "description": "EXCLUSIVE — `>`. Note this differs from /ledger, where it is inclusive.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "created_before",
            "in": "query",
            "required": false,
            "description": "Exclusive — `<`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "reference",
            "in": "query",
            "required": false,
            "description": "Exact match on the reference you sent. Not a prefix and not a search. ≤ 255 characters",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. 1–200 Default: 50.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque. Pass back `next_cursor` from the previous page, or omit it to start again. A malformed cursor is a 400 naming `cursor`, never a silent first page. ≤ 512 characters",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "object": "order",
                      "id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "mode": "live",
                      "status": "completed",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "quantity": 3,
                      "unit_price_cents": 1752,
                      "total_cents": 5256,
                      "list_unit_cents": 1990,
                      "discount_bps": 1195,
                      "price_source": "tier:silver",
                      "tier": "silver",
                      "reference": "BK-99182",
                      "metadata": {},
                      "esims": [
                        {
                          "object": "esim",
                          "iccid": "8944500102030405062",
                          "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                          "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                          "status": "provisioned",
                          "activation": {
                            "smdp_address": "rsp.example.com",
                            "matching_id": "K2-1A9QX-88ZLM",
                            "activation_code": "LPA:1$rsp.example.com$K2-1A9QX-88ZLM",
                            "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                            "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-1A9QX-88ZLM"
                          },
                          "usage": {
                            "data_used_bytes": 0,
                            "data_total_bytes": 5368709120,
                            "voice_used_min": 0,
                            "voice_total_min": null
                          },
                          "activated_at": null,
                          "expires_at": "2026-09-17T06:41:03Z"
                        },
                        {
                          "object": "esim",
                          "iccid": "8944500102030405070",
                          "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                          "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                          "status": "provisioned",
                          "activation": {
                            "smdp_address": "rsp.example.com",
                            "matching_id": "K2-7F4RD-31TVP",
                            "activation_code": "LPA:1$rsp.example.com$K2-7F4RD-31TVP",
                            "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                            "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-7F4RD-31TVP"
                          },
                          "usage": {
                            "data_used_bytes": 0,
                            "data_total_bytes": 5368709120,
                            "voice_used_min": 0,
                            "voice_total_min": null
                          },
                          "activated_at": null,
                          "expires_at": "2026-09-17T06:41:03Z"
                        },
                        {
                          "object": "esim",
                          "iccid": "8944500102030405088",
                          "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                          "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                          "status": "provisioned",
                          "activation": {
                            "smdp_address": "rsp.example.com",
                            "matching_id": "K2-5B2WH-96YKS",
                            "activation_code": "LPA:1$rsp.example.com$K2-5B2WH-96YKS",
                            "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                            "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-5B2WH-96YKS"
                          },
                          "usage": {
                            "data_used_bytes": 0,
                            "data_total_bytes": 5368709120,
                            "voice_used_min": 0,
                            "voice_total_min": null
                          },
                          "activated_at": null,
                          "expires_at": "2026-09-17T06:41:03Z"
                        }
                      ],
                      "failure_code": null,
                      "failure_message": null,
                      "balance_after_cents": 43053,
                      "poll_after_ms": null,
                      "created_at": "2026-08-17T09:14:22Z",
                      "completed_at": "2026-08-17T09:14:27Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/orders/{id}": {
      "get": {
        "operationId": "getOrder",
        "summary": "Where an accepted order actually ends up.",
        "description": "Get an order (the poll)\n\nThis is the delivery mechanism. There are no webhooks on this API, so this is how you learn that an order finished.\nThe loop is: sleep `poll_after_ms`, read, repeat while `poll_after_ms` is not null. Do not enumerate terminal statuses yourself — the API decides what terminal means, and it treats an unrecognised status as terminal so a status added later cannot strand your loop.\n\nNotes:\n- A live key addressing a sandbox order gets 404, not 403 — deliberately, so the error cannot be used to prove an order exists.\n- `esims[]` carries the WHOLE profile, install payload and all — the same object `GET /esims/{iccid}` returns. That is the delivery: when `poll_after_ms` goes null you are already holding everything needed to install what you bought, and re-reading each ICCID afterwards spends read-class calls on data you have. It fills in as profiles land, in the order the units were created.\n- The refund on a `partial` or `failed` order lands in the SAME transaction as the status write, so by the time you can read the status, `GET /balance` already reflects the money.",
        "tags": [
          "Orders"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Must begin `po_`.",
            "schema": {
              "type": "string"
            },
            "example": "po_c7m2k9x4v1b6n3q8w5t0r2j7"
          }
        ],
        "responses": {
          "200": {
            "description": "Partially delivered, and settled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "order",
                  "id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                  "mode": "live",
                  "status": "partial",
                  "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "quantity": 3,
                  "unit_price_cents": 1752,
                  "total_cents": 5256,
                  "list_unit_cents": 1990,
                  "discount_bps": 1195,
                  "price_source": "tier:silver",
                  "tier": "silver",
                  "reference": "BK-99182",
                  "metadata": {},
                  "esims": [
                    {
                      "object": "esim",
                      "iccid": "8944500102030405062",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "provisioned",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-1A9QX-88ZLM",
                        "activation_code": "LPA:1$rsp.example.com$K2-1A9QX-88ZLM",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-1A9QX-88ZLM"
                      },
                      "usage": {
                        "data_used_bytes": 0,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": null,
                      "expires_at": "2026-09-17T06:41:03Z"
                    },
                    {
                      "object": "esim",
                      "iccid": "8944500102030405070",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "provisioned",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-7F4RD-31TVP",
                        "activation_code": "LPA:1$rsp.example.com$K2-7F4RD-31TVP",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-7F4RD-31TVP"
                      },
                      "usage": {
                        "data_used_bytes": 0,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": null,
                      "expires_at": "2026-09-17T06:41:03Z"
                    }
                  ],
                  "failure_code": "supplier_error",
                  "failure_message": "2 of 3 profiles were delivered; the other 1 could not be provisioned and have been returned to your balance.",
                  "balance_after_cents": 44805,
                  "poll_after_ms": null,
                  "created_at": "2026-08-17T09:14:22Z",
                  "completed_at": "2026-08-17T09:22:40Z"
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "order.not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/esims": {
      "get": {
        "operationId": "getEsims",
        "summary": "Every profile you have bought.",
        "description": "List profiles\n\nNewest first, scoped to your account and this key’s mode.\n\nNotes:\n- Lists answer `{ \"data\": [...], \"has_more\": bool, \"next_cursor\": string|null }`. There is no total count anywhere on this API, deliberately — counting costs a second scan of everything the filter matched, and `has_more` answers the only question a paging client has.\n- There is NO `created_before` on this endpoint. `/orders` has one; this does not.\n- `qr_code_data_url` is a full base64 PNG, so a page of these is large. Filter and page accordingly.",
        "tags": [
          "eSIMs"
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by profile state.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "provisioned",
                "installed",
                "active",
                "suspended",
                "expired",
                "depleted",
                "cancelled"
              ]
            },
            "example": "active"
          },
          {
            "name": "order_id",
            "in": "query",
            "required": false,
            "description": "Must begin `po_`, else a 400 naming `order_id`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "created_after",
            "in": "query",
            "required": false,
            "description": "EXCLUSIVE — `>`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size. 1–200 Default: 50.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Opaque. Pass back `next_cursor` from the previous page, or omit it to start again. A malformed cursor is a 400 naming `cursor`, never a silent first page. ≤ 512 characters",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "data": [
                    {
                      "object": "esim",
                      "iccid": "8944500102030405062",
                      "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                      "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                      "status": "active",
                      "activation": {
                        "smdp_address": "rsp.example.com",
                        "matching_id": "K2-1A9QX-88ZLM",
                        "activation_code": "LPA:1$rsp.example.com$K2-1A9QX-88ZLM",
                        "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                        "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-1A9QX-88ZLM"
                      },
                      "usage": {
                        "data_used_bytes": 128974848,
                        "data_total_bytes": 5368709120,
                        "voice_used_min": 0,
                        "voice_total_min": null
                      },
                      "activated_at": "2026-08-18T06:41:03Z",
                      "expires_at": "2026-09-17T06:41:03Z"
                    }
                  ],
                  "has_more": false,
                  "next_cursor": null
                }
              }
            }
          },
          "400": {
            "description": "request.invalid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    },
    "/esims/{iccid}": {
      "get": {
        "operationId": "getEsim",
        "summary": "Everything needed to install it, and how much is left.",
        "description": "Get one profile\n\nAddressed by ICCID rather than by an internal id, because the ICCID is what your own support process already has: it is on your customer’s screen.\nThe install payload is complete — an SM-DP+ address and matching id for manual entry, a full `LPA:` activation code, a scannable QR as a data URL, and an Apple universal link that installs the profile in one tap on iOS.\n\nNotes:\n- Byte counters are JSON NUMBERS on this API. They are strings on the consumer API — if you have integrated both, they are not the same type.\n- `apple_universal_link` is a pure transform of the activation code and is null when there is no activation code.\n- Usage is read from our own rows, refreshed by a 30-minute sync, so it can be up to thirty minutes old. A live read is not built. Do not use this to enforce anything that must be exact.",
        "tags": [
          "eSIMs"
        ],
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "description": "The ICCID exactly as it was issued.",
            "schema": {
              "type": "string"
            },
            "example": "8944500102030405062"
          }
        ],
        "responses": {
          "200": {
            "description": "A provisioned profile",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "example": {
                  "object": "esim",
                  "iccid": "8944500102030405062",
                  "order_id": "po_c7m2k9x4v1b6n3q8w5t0r2j7",
                  "plan_id": "pl_c3n8k5x2v9b4m7q1w6t3r0j5",
                  "status": "provisioned",
                  "activation": {
                    "smdp_address": "rsp.example.com",
                    "matching_id": "K2-1A9QX-88ZLM",
                    "activation_code": "LPA:1$rsp.example.com$K2-1A9QX-88ZLM",
                    "qr_code_data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...",
                    "apple_universal_link": "https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA%3A1%24rsp.example.com%24K2-1A9QX-88ZLM"
                  },
                  "usage": {
                    "data_used_bytes": 0,
                    "data_total_bytes": 5368709120,
                    "voice_used_min": 0,
                    "voice_total_min": null
                  },
                  "activated_at": null,
                  "expires_at": "2026-09-17T06:41:03Z"
                }
              }
            }
          },
          "401": {
            "description": "auth.missing, auth.invalid_key, auth.key_expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "auth.ip_not_allowed, partner.not_live, partner.suspended, partner.closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "esim.not_found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limit.exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "x-rate-class": "read"
      }
    }
  }
}
