{
  "openapi": "3.1.0",
  "info": {
    "title": "Aerix SIM API",
    "version": "1.0.0",
    "description": "Order, inspect and manage Aerix physical SIMs and eSIMs from your own systems.\n\n**Compatibility promise.** v1 only ever grows: we add fields, endpoints, query parameters and enum values, and never remove, rename or retype anything. Ignore fields and enum values you do not recognise. Anything incompatible would ship as /v2 with v1 kept running.\n\n**Authentication.** `Authorization: Bearer aerix_live_…`. Keys are created and revoked in the Aerix customer portal (Account, then API keys) and each carries scopes.\n\n**Rate limits.** 600 read and 60 write requests per minute per key; 429 with Retry-After beyond that.\n\n**Errors** are RFC 9457 `application/problem+json`; branch on the stable `code` field.\n\n**Identifiers** (ICCID, IMSI) are strings. Timestamps are RFC 3339 UTC.",
    "contact": {
      "name": "Aerix support",
      "email": "support@aerix.uk",
      "url": "https://www.aerix.uk"
    }
  },
  "servers": [
    {
      "url": "https://api.aerix.uk/v1",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "SIMs"
    },
    {
      "name": "Orders"
    },
    {
      "name": "Profiles"
    },
    {
      "name": "Account"
    },
    {
      "name": "Events"
    },
    {
      "name": "Webhooks"
    }
  ],
  "paths": {
    "/sims": {
      "get": {
        "tags": [
          "SIMs"
        ],
        "operationId": "listSims",
        "summary": "List SIMs",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque; from next_cursor"
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/SimState"
            }
          },
          {
            "name": "form",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "physical",
                "esim"
              ]
            }
          },
          {
            "name": "site",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "iccid",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "imsi",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "profile",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Sim"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as ?cursor= for the next page; null on the last page."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/sims/{iccid}": {
      "get": {
        "tags": [
          "SIMs"
        ],
        "operationId": "getSim",
        "summary": "Get a SIM",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sim"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "SIMs"
        ],
        "operationId": "updateSim",
        "summary": "Set or clear a SIM's label",
        "security": [
          {
            "bearer": [
              "sims:write"
            ]
          }
        ],
        "x-required-scope": "sims:write",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "label"
                ],
                "properties": {
                  "label": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sim"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/sims/{iccid}/suspend": {
      "post": {
        "tags": [
          "SIMs"
        ],
        "operationId": "suspendSim",
        "summary": "Suspend a SIM",
        "description": "Bars the subscriber on the Aerix-run core serving it. Allowed from active. A SIM on your own core returns 409 core_not_managed: bar it there.",
        "security": [
          {
            "bearer": [
              "sims:write"
            ]
          }
        ],
        "x-required-scope": "sims:write",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Unique per logical request; reuse it on retry. The first response is replayed for 24 hours (Idempotent-Replayed: true)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sim"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key reused with a different request (code idempotency_conflict)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "The serving core or SM-DP+ did not confirm (code core_unavailable); nothing changed, retry",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/sims/{iccid}/resume": {
      "post": {
        "tags": [
          "SIMs"
        ],
        "operationId": "resumeSim",
        "summary": "Resume a suspended SIM",
        "description": "Restores the subscriber on the Aerix-run core. Allowed from suspended.",
        "security": [
          {
            "bearer": [
              "sims:write"
            ]
          }
        ],
        "x-required-scope": "sims:write",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Unique per logical request; reuse it on retry. The first response is replayed for 24 hours (Idempotent-Replayed: true)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sim"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key reused with a different request (code idempotency_conflict)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "The serving core or SM-DP+ did not confirm (code core_unavailable); nothing changed, retry",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/sims/{iccid}/retire": {
      "post": {
        "tags": [
          "SIMs"
        ],
        "operationId": "retireSim",
        "summary": "Retire a SIM",
        "description": "Bars the subscriber on any Aerix-run core, retires a Simartis eSIM at the SM-DP+, and marks the SIM retired so its identity is never reused. Terminal.",
        "security": [
          {
            "bearer": [
              "sims:write"
            ]
          }
        ],
        "x-required-scope": "sims:write",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Unique per logical request; reuse it on retry. The first response is replayed for 24 hours (Idempotent-Replayed: true)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Sim"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key reused with a different request (code idempotency_conflict)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "The serving core or SM-DP+ did not confirm (code core_unavailable); nothing changed, retry",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/sims/{iccid}/credentials": {
      "get": {
        "tags": [
          "SIMs"
        ],
        "operationId": "getSimCredentials",
        "summary": "Get a physical SIM's credentials",
        "description": "K, OPc and the SUCI home-network public key, for customers running their own core. Every call is audited. eSIM keys are held by the SM-DP+ and are not exportable (409 not_physical).",
        "security": [
          {
            "bearer": [
              "credentials:read"
            ]
          }
        ],
        "x-required-scope": "credentials:read",
        "parameters": [
          {
            "name": "iccid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SimCredentials"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/orders": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "listOrders",
        "summary": "List SIM orders",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Opaque; from next_cursor"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/OrderStatus"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Order"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as ?cursor= for the next page; null on the last page."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Orders"
        ],
        "operationId": "createOrder",
        "summary": "Order physical SIMs on account",
        "description": "Places an order on your Aerix credit account; it is invoiced (Stripe, payment terms per your account) rather than paid at checkout. Fails with 402 credit_limit_exceeded if it would take you over your limit, 403 no_credit_account without an approved account, and 403 account_on_hold while an invoice is overdue. eSIM orders (form \"esim\": quantity, spn, mcc, mnc, start_imsi; no shipping) return 409 esim_orders_unavailable until eSIM ordering opens, and 409 imsi_in_use if part of the IMSI range is taken. Once open, an eSIM order moves accepted → provisioning (the profiles are created at our SM-DP+) → ready; each eSIM then appears in GET /v1/sims with esim.activation_code, and GET /v1/sims/{iccid}/credentials returns its K/OPc for your core.",
        "security": [
          {
            "bearer": [
              "orders:write"
            ]
          }
        ],
        "x-required-scope": "orders:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Unique per logical request; reuse it on retry. The first response is replayed for 24 hours (Idempotent-Replayed: true)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrderRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "402": {
            "description": "Would exceed your credit limit (code credit_limit_exceeded)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key reused with a different request (code idempotency_conflict)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/orders/{id}": {
      "get": {
        "tags": [
          "Orders"
        ],
        "operationId": "getOrder",
        "summary": "Get an order",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/profiles": {
      "get": {
        "tags": [
          "Profiles"
        ],
        "operationId": "listProfiles",
        "summary": "List SIM profiles",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Profile"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as ?cursor= for the next page; null on the last page."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/account": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getAccount",
        "summary": "The key's customer, scopes and credit account",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listEvents",
        "summary": "Events after a sequence number",
        "description": "Every event, in order, for polling or catching up after webhook downtime. Pass the last seq you processed as after.",
        "security": [
          {
            "bearer": [
              "sims:read"
            ]
          }
        ],
        "x-required-scope": "sims:read",
        "parameters": [
          {
            "name": "after",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_after"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "next_after": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "listWebhooks",
        "summary": "List webhook endpoints",
        "security": [
          {
            "bearer": [
              "webhooks:write"
            ]
          }
        ],
        "x-required-scope": "webhooks:write",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "data",
                    "next_cursor"
                  ],
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    },
                    "next_cursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Pass as ?cursor= for the next page; null on the last page."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "createWebhook",
        "summary": "Add a webhook endpoint",
        "description": "Events are POSTed as JSON with X-Aerix-Event and X-Aerix-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" keyed with the secret>. Reply 2xx within 10 s; failures retry with backoff for 24 hours. The secret is returned only here.",
        "security": [
          {
            "bearer": [
              "webhooks:write"
            ]
          }
        ],
        "x-required-scope": "webhooks:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "description": "Unique per logical request; reuse it on retry. The first response is replayed for 24 hours (Idempotent-Replayed: true)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Public https URL"
                  },
                  "event_types": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/EventType"
                    },
                    "description": "Empty or omitted = all"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created; store the secret",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Webhook"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "secret": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (code invalid_request)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "409": {
            "description": "Conflict: invalid_transition, core_not_managed, not_physical, esim_orders_unavailable, imsi_in_use or idempotency_in_progress",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Idempotency-Key reused with a different request (code idempotency_conflict)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/webhooks/{id}": {
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "operationId": "deleteWebhook",
        "summary": "Stop deliveries to a webhook endpoint",
        "security": [
          {
            "bearer": [
              "webhooks:write"
            ]
          }
        ],
        "x-required-scope": "webhooks:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "deleted": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, unknown, revoked or expired key (code unauthorized)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "403": {
            "description": "Key lacks the required scope (code insufficient_scope)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found, or not owned by this key's customer (code not_found)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (code rate_limited); see Retry-After",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Scopes: `sims:read` (List and read SIMs, orders, profiles and the account); `sims:write` (Label, suspend, resume, retire and move SIMs); `orders:write` (Place SIM orders on account); `esims:write` (Issue eSIMs and read activation codes); `credentials:read` (Read SIM credentials (K, OPc, SUCI key). Audited.); `webhooks:write` (Manage webhook endpoints)"
      }
    },
    "schemas": {
      "Problem": {
        "type": "object",
        "required": [
          "type",
          "title",
          "status",
          "code"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable code. New codes may be added."
          },
          "detail": {
            "type": "string"
          }
        }
      },
      "SimState": {
        "type": "string",
        "enum": [
          "ordered",
          "provisioning",
          "ready",
          "active",
          "suspended",
          "retired",
          "failed",
          "unknown"
        ],
        "description": "Lifecycle state, shared by physical SIMs and eSIMs. New states may be added."
      },
      "OrderStatus": {
        "type": "string",
        "enum": [
          "accepted",
          "provisioning",
          "ready",
          "dispatched",
          "failed",
          "cancelled"
        ],
        "description": "New statuses may be added."
      },
      "Sim": {
        "type": "object",
        "required": [
          "iccid",
          "imsi",
          "form",
          "state",
          "site",
          "label",
          "created_at",
          "physical",
          "esim"
        ],
        "properties": {
          "iccid": {
            "type": "string",
            "examples": [
              "89440900100000070988"
            ]
          },
          "imsi": {
            "type": [
              "string",
              "null"
            ],
            "examples": [
              "234430000007097"
            ]
          },
          "form": {
            "type": "string",
            "enum": [
              "physical",
              "esim"
            ]
          },
          "state": {
            "$ref": "#/components/schemas/SimState"
          },
          "site": {
            "type": [
              "string",
              "null"
            ],
            "description": "Aerix-run site whose core serves the SIM, if any"
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "physical": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "batch_id": {
                "type": "string",
                "format": "uuid"
              },
              "order_id": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uuid"
              },
              "msisdn": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "profile": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "esim": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "provider": {
                "type": "string"
              },
              "install_state": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "released, downloaded, installed, enabled, disabled, deleted…"
              },
              "eid": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "released_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "installed_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              },
              "device": {
                "type": "object",
                "properties": {
                  "brand": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "model": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "os": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              },
              "activation_code": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "SGP.22 activation code (LPA:1$<SM-DP+>$<matching ID>) for the device or QR code while the profile waits to be downloaded; null once downloaded. Treat it as a secret."
              }
            }
          }
        }
      },
      "SimCredentials": {
        "type": "object",
        "required": [
          "iccid",
          "imsi",
          "k",
          "opc",
          "suci"
        ],
        "properties": {
          "iccid": {
            "type": "string"
          },
          "imsi": {
            "type": "string"
          },
          "k": {
            "type": "string",
            "description": "128-bit subscriber key, hex"
          },
          "opc": {
            "type": "string",
            "description": "128-bit OPc, hex"
          },
          "suci": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "scheme": {
                "type": "string",
                "enum": [
                  "profile_a",
                  "profile_b"
                ]
              },
              "key_id": {
                "type": "integer"
              },
              "public_key_hex": {
                "type": "string"
              }
            }
          }
        }
      },
      "Order": {
        "type": "object",
        "required": [
          "id",
          "form",
          "status",
          "quantity",
          "plmn",
          "spn",
          "start_imsi",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "form": {
            "type": "string",
            "enum": [
              "physical",
              "esim"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/OrderStatus"
          },
          "quantity": {
            "type": "integer"
          },
          "plmn": {
            "type": "string",
            "examples": [
              "23443"
            ]
          },
          "spn": {
            "type": "string"
          },
          "start_imsi": {
            "type": "string"
          },
          "profile": {
            "type": [
              "string",
              "null"
            ]
          },
          "batch_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "amount_total_pence": {
            "type": "integer"
          },
          "currency": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "dispatched_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "invoice": {
            "type": [
              "object",
              "null"
            ],
            "description": "Orders on account; null for orders paid at checkout",
            "properties": {
              "status": {
                "type": "string",
                "description": "pending, open, paid, void, uncollectible"
              },
              "due_at": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          }
        }
      },
      "Profile": {
        "type": "object",
        "required": [
          "id",
          "plmn",
          "spn",
          "suci"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "plmn": {
            "type": [
              "string",
              "null"
            ]
          },
          "spn": {
            "type": [
              "string",
              "null"
            ]
          },
          "suci": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "scheme": {
                "type": "string"
              },
              "key_id": {
                "type": "integer"
              },
              "public_key_hex": {
                "type": "string"
              }
            }
          }
        }
      },
      "OrderRequest": {
        "type": "object",
        "required": [
          "form",
          "quantity",
          "spn",
          "mcc",
          "mnc",
          "start_imsi",
          "shipping"
        ],
        "properties": {
          "form": {
            "type": "string",
            "enum": [
              "physical",
              "esim"
            ]
          },
          "quantity": {
            "type": "integer",
            "minimum": 1,
            "maximum": 50
          },
          "spn": {
            "type": "string",
            "maxLength": 16,
            "description": "Network name shown on handsets (ASCII)"
          },
          "mcc": {
            "type": "string",
            "pattern": "^[0-9]{3}$"
          },
          "mnc": {
            "type": "string",
            "pattern": "^[0-9]{2}$",
            "description": "2-digit MNCs only for now"
          },
          "start_imsi": {
            "type": "string",
            "pattern": "^[0-9]{15}$",
            "description": "First IMSI; must start with MCC+MNC. IMSIs run sequentially."
          },
          "suci_calculation": {
            "type": "string",
            "enum": [
              "sim",
              "device"
            ],
            "default": "sim"
          },
          "reference": {
            "type": "string",
            "maxLength": 100,
            "description": "Your purchase order or reference"
          },
          "shipping": {
            "type": "object",
            "required": [
              "name",
              "line1",
              "city",
              "postcode",
              "country"
            ],
            "properties": {
              "name": {
                "type": "string"
              },
              "line1": {
                "type": "string"
              },
              "line2": {
                "type": "string"
              },
              "city": {
                "type": "string"
              },
              "postcode": {
                "type": "string"
              },
              "country": {
                "type": "string",
                "description": "ISO 3166-1 alpha-2; UK, Europe and USA"
              },
              "phone": {
                "type": "string"
              }
            }
          }
        }
      },
      "EventType": {
        "type": "string",
        "enum": [
          "order.created",
          "order.updated",
          "sim.state_changed",
          "sim.updated"
        ],
        "description": "New event types may be added."
      },
      "Event": {
        "type": "object",
        "required": [
          "id",
          "seq",
          "type",
          "created_at",
          "data"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "seq": {
            "type": "integer",
            "description": "Increasing per account"
          },
          "type": {
            "$ref": "#/components/schemas/EventType"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "type": "object"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "required": [
          "id",
          "url",
          "event_types",
          "created_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "event_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventType"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Account": {
        "type": "object",
        "required": [
          "customer_id",
          "name",
          "credit",
          "key"
        ],
        "properties": {
          "customer_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": [
              "string",
              "null"
            ]
          },
          "credit": {
            "type": [
              "object",
              "null"
            ],
            "description": "Null until Aerix approves a credit account",
            "properties": {
              "limit_pence": {
                "type": "integer"
              },
              "currency": {
                "type": "string"
              },
              "payment_terms_days": {
                "type": "integer"
              },
              "on_hold": {
                "type": "boolean"
              },
              "exposure_pence": {
                "type": "integer",
                "description": "Accepted and unpaid orders"
              },
              "headroom_pence": {
                "type": "integer",
                "description": "limit minus exposure"
              },
              "overdue": {
                "type": "boolean"
              }
            }
          },
          "key": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  }
}