{
  "openapi": "3.1.0",
  "info": {
    "title": "CodeB Sovereign Communications — Public API",
    "version": "2026-07-20 round-b-2026-07-20-cwt",
    "summary": "REST + WebSocket + OpenID Connect + OpenID4VP + OpenID4VCI + LOTL + Federation + SIP-over-WebSocket surface, all multi-tenant by Host header. Aloaha-owned, built from scratch, hosted in Malta.",
    "description": "This spec covers every publicly reachable endpoint exposed by the CodeB Sovereign Communications platform: the OIDC provider + EU Wallet verifier (oidc.ashx), the OpenID4VCI issuer (vci.ashx), the LOTL trust-anchor cache (lotl.ashx), the RP-certificate CA (rp-cert.ashx), the chat + file-transfer platform (chat.ashx + chat-ws.ashx + chat-invite/widget/email .ashx), the property-management inbox (pms.ashx), the per-tenant admin surface (signal.ashx), the v1 REST outbound-AI + numbers + transcripts (api.ashx/v1), and the bridge health passthroughs (/sip-tls/health, /sip-ws/health, /sfu/health). Every endpoint is tenant-scoped by the Host header; there is no cross-tenant data access. Import this file into Postman, Insomnia, Swagger UI or any OpenAPI-3-compatible tool to explore the surface. Machine-generated clients welcome. Authentication: `oidc-bearer` = an OIDC access-token minted by /oauth2/v1/token; `hmac-admin` = X-CodeB-Admin-Signature header = hex(HMAC-SHA256(WebPhone:AdminSharedSecret, bucketName + '|' + Host)). Many admin endpoints accept EITHER bearer OR HMAC.",
    "contact": {
      "name": "Aloaha Limited",
      "url": "https://www.aloaha.com/contact.html"
    },
    "license": {
      "name": "Proprietary — Aloaha Limited",
      "url": "https://www.aloaha.com/legal.html"
    },
    "termsOfService": "https://www.aloaha.com/legal.html"
  },
  "servers": [
    {
      "url": "https://phone.aloaha.com",
      "description": "Primary production tenant"
    },
    {
      "url": "https://phone.codeb.io",
      "description": "Development / conformance tenant"
    },
    {
      "url": "https://{tenant}",
      "description": "Any tenant domain — replace {tenant} with your provisioned host",
      "variables": {
        "tenant": {
          "default": "phone.aloaha.com"
        }
      }
    }
  ],
  "tags": [
    {
      "name": "oidc-op",
      "description": "OpenID Connect Provider — authorize/token/userinfo/discovery/JWKS"
    },
    {
      "name": "oidc-federation",
      "description": "OpenID Federation 1.0 — entity statement, trust chain"
    },
    {
      "name": "eu-wallet-verifier",
      "description": "OpenID4VP 1.0 + HAIP 1.0 verifier — vp-start / vp-request / vp-response"
    },
    {
      "name": "eu-wallet-issuer",
      "description": "OpenID4VCI issuer — offer / token / credential / jwks / metadata"
    },
    {
      "name": "network-access",
      "description": "EUDI §5f Network-Access-via-PID — scope=network_access, signed WiFi/APN configs"
    },
    {
      "name": "lotl",
      "description": "EU List of Trusted Lists cache + anchor resolution"
    },
    {
      "name": "rp-cert",
      "description": "RP verifier certificate CA (WRPAC-lite)"
    },
    {
      "name": "sip-admin",
      "description": "Tenant admin — trunks, users, routes, ACL, whitelist"
    },
    {
      "name": "chat",
      "description": "Chat platform — DM, groups, file transfers, invitations"
    },
    {
      "name": "chat-widget",
      "description": "Anonymous 'Chat with us' visitor widget"
    },
    {
      "name": "chat-email",
      "description": "Email-to-chat channel (SMTP-in / IMAP)"
    },
    {
      "name": "pms",
      "description": "Property-Management inbox integration"
    },
    {
      "name": "v1-rest",
      "description": "v1 REST — outbound AI, numbers, transcripts, routes, webhooks"
    },
    {
      "name": "bridge-health",
      "description": "Read-only bridge health passthroughs"
    },
    {
      "name": "well-known",
      "description": "Standardised /.well-known/* aliases"
    }
  ],
  "components": {
    "securitySchemes": {
      "oidcBearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "OIDC access token minted by /oauth2/v1/token. Tenant-scoped by Host header. Also accepts ak_-prefixed personal API keys on the v1 REST surface."
      },
      "hmacAdmin": {
        "type": "apiKey",
        "in": "header",
        "name": "X-CodeB-Admin-Signature",
        "description": "Hex(HMAC-SHA256(WebPhone:AdminSharedSecret, bucketName + '|' + Host)). Bucket name is documented per-endpoint. This scheme is designed for machine-to-machine admin automation (CI, cron, back-office scripts) where OIDC bearer flow isn't practical."
      },
      "credentialAccessToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "opaque",
        "description": "OAuth 2.0 access token minted by /vci.ashx?token via pre-authorized_code grant. Used only on POST /vci.ashx?credential."
      }
    },
    "parameters": {
      "host": {
        "name": "Host",
        "in": "header",
        "required": false,
        "description": "Tenant selector. Every endpoint is tenant-scoped by the Host header. Missing/unknown Host falls back to primary tenant per per-domain WebPhoneSettings resolution.",
        "schema": {
          "type": "string",
          "example": "phone.aloaha.com"
        }
      }
    },
    "schemas": {
      "OidcDiscovery": {
        "type": "object",
        "required": [
          "issuer",
          "authorization_endpoint",
          "token_endpoint",
          "userinfo_endpoint",
          "jwks_uri",
          "response_types_supported",
          "subject_types_supported",
          "id_token_signing_alg_values_supported"
        ],
        "properties": {
          "issuer": {
            "type": "string",
            "format": "uri"
          },
          "authorization_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "token_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "userinfo_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "jwks_uri": {
            "type": "string",
            "format": "uri"
          },
          "end_session_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "revocation_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "introspection_endpoint": {
            "type": "string",
            "format": "uri"
          },
          "request_parameter_supported": {
            "type": "boolean"
          },
          "request_object_signing_alg_values_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "plain",
                "S256"
              ]
            }
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "openid, profile, email, offline_access, network_access, ..."
          },
          "grant_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Jwks": {
        "type": "object",
        "required": [
          "keys"
        ],
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "EntityStatementJwt": {
        "type": "string",
        "description": "Signed ES256 JWT per OpenID Federation 1.0 §3.1. Content-Type: application/entity-statement+jwt. Cacheable public, max-age=3600 (matches exp)."
      },
      "VpStartResponse": {
        "type": "object",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "request_uri": {
            "type": "string",
            "format": "uri"
          },
          "openid4vp_url": {
            "type": "string",
            "description": "openid4vp://... deep link for the wallet"
          },
          "expires_in": {
            "type": "integer"
          }
        }
      },
      "VpResponseResult": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "verified",
              "error"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "presentation": {
            "type": "object"
          },
          "network_config": {
            "$ref": "#/components/schemas/NetworkConfig",
            "description": "Present only when scope=network_access was requested at vp-start."
          },
          "sso_assertion": {
            "type": "string",
            "description": "Opaque token that a downstream RP can redeem via OIDC code exchange."
          }
        }
      },
      "NetworkConfig": {
        "type": "object",
        "description": "Signed WiFi / APN / VPN configuration issued to a wallet after successful PID presentation with scope=network_access. Signature is a compact JWS (ES256, x5c chain) — wallet verifies against the tenant verifier cert, then provisions the network profile on the device.",
        "required": [
          "profile_id",
          "network_type",
          "expires_at",
          "signature"
        ],
        "properties": {
          "profile_id": {
            "type": "string",
            "description": "Tenant-configured profile name (e.g. 'guest-wifi-hotel', 'corporate-vpn')."
          },
          "network_type": {
            "type": "string",
            "enum": [
              "wifi-wpa2-eap",
              "wifi-wpa3-eap",
              "wifi-wpa2-psk",
              "wifi-hotspot20",
              "apn-4g",
              "apn-5g",
              "openvpn",
              "wireguard"
            ]
          },
          "ssid": {
            "type": "string",
            "description": "WiFi SSID (when network_type is wifi-*)"
          },
          "eap_method": {
            "type": "string",
            "description": "PEAP / TTLS / TLS / MSCHAPv2 (WPA2/3-EAP profiles)"
          },
          "identity": {
            "type": "string",
            "description": "Derived from PID claims per tenant policy (e.g. given_name.family_name@tenant.example)"
          },
          "password_or_psk": {
            "type": "string",
            "description": "Ephemeral per-session credential; not present for cert-based EAP-TLS."
          },
          "ca_certificate_pem": {
            "type": "string",
            "description": "Radius CA the wallet should trust for the corporate WPA2-EAP server."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Absolute expiry — wallet MUST discard the profile after this timestamp."
          },
          "signature": {
            "type": "string",
            "description": "Compact JWS (ES256, x5c chain to tenant verifier cert) over the canonicalised config body."
          }
        }
      },
      "LotlManifest": {
        "type": "object",
        "properties": {
          "as_of": {
            "type": "string",
            "format": "date-time"
          },
          "next_refresh_at": {
            "type": "string",
            "format": "date-time"
          },
          "anchor_count": {
            "type": "integer"
          },
          "countries_covered": {
            "type": "array",
            "items": {
              "type": "string",
              "description": "ISO 3166-1 alpha-2"
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "OAuth 2.0 / OIDC error code where applicable (invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_response_type, unsupported_grant_type, invalid_scope, access_denied, login_required, ...)"
          },
          "error_description": {
            "type": "string"
          },
          "error_uri": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "WalletClientsConfig": {
        "type": "object",
        "description": "Per-tenant wallet client_id whitelist. Auto-created at App_Data/<tenant>/wallet-clients.json with the default ['aloaha-web-wallet'] on the first credential-issuance request when absent. Add wallet vendors by editing the file (changes picked up within 5 min). Malformed/empty files fall back to the hardcoded default WITHOUT being overwritten (operator may be mid-edit). Cached 5 minutes per tenant.",
        "required": [
          "client_ids"
        ],
        "properties": {
          "client_ids": {
            "type": "array",
            "description": "Wallet client_ids accepted at /vci.ashx?par and /vci.ashx?authorize.",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "example": [
              "aloaha-web-wallet",
              "some-other-wallet-vendor-id"
            ]
          },
          "_schema": {
            "type": "string",
            "description": "Optional. Pointer to this schema. Ignored by the loader.",
            "format": "uri"
          },
          "_notes": {
            "type": "string",
            "description": "Optional. Free-form operator notes. Ignored by the loader."
          }
        },
        "additionalProperties": false
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing/invalid Bearer OR missing/invalid HMAC signature. WWW-Authenticate: Bearer realm=\"codeb-admin\".",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Authenticated but insufficient privileges (e.g. admin op requiring superuser).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "429 Too Many Requests. Public endpoints have per-IP rate limits; retry after the interval in Retry-After.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            },
            "description": "seconds"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "security": [],
  "paths": {
    "/.well-known/openid-configuration": {
      "get": {
        "tags": [
          "well-known",
          "oidc-op"
        ],
        "operationId": "getDiscovery",
        "summary": "OIDC discovery document (alias: /oauth2/v1/.well-known/openid-configuration + /oidc.ashx?action=discovery)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OidcDiscovery"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/jwks.json": {
      "get": {
        "tags": [
          "well-known",
          "oidc-op"
        ],
        "operationId": "getJwks",
        "summary": "JWKS (alias: /oauth2/v1/keys + /oidc.ashx?action=jwks)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Jwks"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-federation": {
      "get": {
        "tags": [
          "well-known",
          "oidc-federation"
        ],
        "operationId": "getFederationEntity",
        "summary": "OpenID Federation 1.0 §3.1 entity statement (alias: /oidc.ashx?action=federation-entity)",
        "responses": {
          "200": {
            "description": "Signed ES256 entity statement JWT",
            "content": {
              "application/entity-statement+jwt": {
                "schema": {
                  "$ref": "#/components/schemas/EntityStatementJwt"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/eudiw-verifier-metadata": {
      "get": {
        "tags": [
          "well-known",
          "eu-wallet-verifier"
        ],
        "operationId": "getVerifierMetadata",
        "summary": "EUDI verifier metadata (alias .json)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-credential-issuer": {
      "get": {
        "tags": [
          "well-known",
          "eu-wallet-issuer"
        ],
        "operationId": "getIssuerMetadata",
        "summary": "OpenID4VCI credential issuer metadata (alias: /vci.ashx?metadata)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-credential-issuer/jwks": {
      "get": {
        "tags": [
          "well-known",
          "eu-wallet-issuer"
        ],
        "operationId": "getIssuerJwks",
        "summary": "OpenID4VCI issuer JWKS (alias: /vci.ashx?jwks)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Jwks"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openapi.json": {
      "get": {
        "tags": [
          "well-known"
        ],
        "operationId": "getOpenapi",
        "summary": "This document — machine-readable API spec (alias: /openapi.json)",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/dnt-policy.txt": {
      "get": {
        "tags": [
          "well-known"
        ],
        "operationId": "getDntPolicy",
        "summary": "EFF Do Not Track compliance policy",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {}
            }
          }
        }
      }
    },
    "/.well-known/traffic-advice": {
      "get": {
        "tags": [
          "well-known"
        ],
        "operationId": "getTrafficAdvice",
        "summary": "Chrome Privacy Sandbox prefetch-proxy advice",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/trafficadvice+json": {}
            }
          }
        }
      }
    },
    "/oauth2/v1/authorize": {
      "get": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "authorize",
        "summary": "Authorization endpoint (RFC 6749 §3.1). Aliases: /oidc.ashx?action=authorize.",
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "code",
                "id_token",
                "code id_token"
              ]
            }
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "openid + optional profile/email/offline_access/network_access"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "nonce",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "prompt",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "none",
                "login",
                "consent",
                "select_account"
              ]
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "S256",
                "plain"
              ]
            }
          },
          {
            "name": "request",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Signed JWT request object (RFC 9101). Merged with query params — query wins on conflict."
            }
          },
          {
            "name": "id_token_hint",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "max_age",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to redirect_uri (with code|error) OR to /login.html (session bootstrap)."
          },
          "400": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "authorizePost",
        "summary": "Same as GET /authorize but form-encoded",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "302": {
            "description": "Redirect (see GET)"
          }
        }
      }
    },
    "/oauth2/v1/token": {
      "post": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "token",
        "summary": "Token endpoint (RFC 6749 §3.2) — supports authorization_code, refresh_token, client_credentials, RFC 7523 jwt-bearer, urn:ietf:params:oauth:grant-type:pre-authorized_code (OID4VCI). Alias: /oidc.ashx?action=token.",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string"
                  },
                  "redirect_uri": {
                    "type": "string"
                  },
                  "code_verifier": {
                    "type": "string"
                  },
                  "refresh_token": {
                    "type": "string"
                  },
                  "assertion": {
                    "type": "string"
                  },
                  "pre-authorized_code": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access + optionally id + refresh tokens",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/oauth2/v1/userinfo": {
      "get": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "userinfo",
        "summary": "Userinfo endpoint (RFC 6749 §7). Alias: /oidc.ashx?action=userinfo.",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Claims JSON",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/oauth2/v1/logout": {
      "get": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "endSession",
        "summary": "End Session endpoint (OIDC RP-Initiated Logout 1.0). Alias: /oidc.ashx?action=end_session.",
        "responses": {
          "200": {
            "description": "OK"
          },
          "302": {
            "description": "Redirect to post_logout_redirect_uri"
          }
        }
      }
    },
    "/oauth2/v1/revoke": {
      "post": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "revoke",
        "summary": "RFC 7009 token revocation. Alias: /oidc.ashx?action=revoke.",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (always 200 per RFC)"
          }
        }
      }
    },
    "/oauth2/v1/introspect": {
      "post": {
        "tags": [
          "oidc-op"
        ],
        "operationId": "introspect",
        "summary": "RFC 7662 token introspection. Alias: /oidc.ashx?action=introspect.",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{active:boolean, ...}",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/oidc.ashx?action=vp-start": {
      "get": {
        "tags": [
          "eu-wallet-verifier"
        ],
        "operationId": "vpStart",
        "summary": "Start an OpenID4VP session (creates request_uri + openid4vp:// deep link for the wallet).",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "vp-start"
              ]
            }
          },
          {
            "name": "preset",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Named DCQL preset (e.g. 'pid-basic', 'age-over-18', 'network_access-hotel-guest')"
            }
          },
          {
            "name": "client_id_prefix",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "x509_hash",
                "x509_san_dns"
              ],
              "default": "x509_hash"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "openid or openid network_access — network_access triggers signed NetworkConfig issuance on successful presentation"
            }
          },
          {
            "name": "network_profile",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "Named profile from network-policies.json when scope includes network_access"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Session created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VpStartResponse"
                }
              }
            }
          }
        }
      }
    },
    "/oidc.ashx?action=vp-request": {
      "get": {
        "tags": [
          "eu-wallet-verifier"
        ],
        "operationId": "vpRequest",
        "summary": "Retrieve the signed Authorization Request JWT (JAR).",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "vp-request"
              ]
            }
          },
          {
            "name": "session_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Signed JAR",
            "content": {
              "application/oauth-authz-req+jwt": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/oidc.ashx?action=vp-response": {
      "post": {
        "tags": [
          "eu-wallet-verifier"
        ],
        "operationId": "vpResponse",
        "summary": "Wallet POSTs its verifiable presentation here (direct_post or direct_post.jwt). The vp_token is auto-detected: SD-JWT VC compact serialization or mDoc CBOR (routed to MDocVerifier.Verify when the body starts with a CBOR map header 0xA0-0xBB). mDoc verification requires trust anchors under App_Data/<tenant>/trust/mdoc-issuers/*.cer; missing directory returns HTTP 501 mdoc_verify_not_configured. Response includes NetworkConfig when scope=network_access was requested.",
        "requestBody": {
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object"
              }
            },
            "application/jose": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verified",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VpResponseResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "501": {
            "description": "mdoc_verify_not_configured -- add issuer certs under App_Data/<tenant>/trust/mdoc-issuers/ to enable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/oidc.ashx?action=network-config": {
      "get": {
        "tags": [
          "network-access"
        ],
        "operationId": "networkConfig",
        "summary": "Retrieve the signed NetworkConfig for a completed network_access session (idempotent, cacheable until config.expires_at).",
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "network-config"
              ]
            }
          },
          {
            "name": "session_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkConfig"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or expired session"
          }
        }
      }
    },
    "/vci.ashx?metadata": {
      "get": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issuerMetadata",
        "summary": "OpenID4VCI credential issuer metadata (alias /.well-known/openid-credential-issuer). Advertises authorization_endpoint, pushed_authorization_request_endpoint, grant_types_supported (both authorization_code and urn:ietf:params:oauth:grant-type:pre-authorized_code), code_challenge_methods_supported=[S256], response_types_supported=[code], and token_endpoint_auth_methods_supported=[none] (public client, PKCE mandatory).",
        "parameters": [
          {
            "name": "metadata",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/vci.ashx?jwks": {
      "get": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issuerJwks",
        "summary": "OpenID4VCI issuer JWKS (alias /.well-known/openid-credential-issuer/jwks).",
        "parameters": [
          {
            "name": "jwks",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Jwks"
                }
              }
            }
          }
        }
      }
    },
    "/vci.ashx?token": {
      "post": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issuerToken",
        "summary": "Token endpoint per OpenID4VCI. Supports both authorization_code (with PKCE) and urn:ietf:params:oauth:grant-type:pre-authorized_code grants.",
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "authorization_code",
                      "urn:ietf:params:oauth:grant-type:pre-authorized_code"
                    ]
                  },
                  "code": {
                    "type": "string",
                    "description": "Present when grant_type=authorization_code. Single-use; consumed even on failed exchange."
                  },
                  "redirect_uri": {
                    "type": "string",
                    "description": "Byte-exact match with PAR/authorize value when grant_type=authorization_code."
                  },
                  "code_verifier": {
                    "type": "string",
                    "minLength": 43,
                    "maxLength": 128,
                    "description": "PKCE verifier for authorization_code grant."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Required for authorization_code; must match the whitelisted client from PAR."
                  },
                  "pre-authorized_code": {
                    "type": "string",
                    "description": "Present when grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access token + fresh c_nonce (same shape for both grants).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "access_token",
                    "token_type",
                    "expires_in"
                  ],
                  "properties": {
                    "access_token": {
                      "type": "string"
                    },
                    "token_type": {
                      "type": "string",
                      "enum": [
                        "Bearer"
                      ]
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "c_nonce": {
                      "type": "string"
                    },
                    "c_nonce_expires_in": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_grant / invalid_client / invalid_request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/vci.ashx?credential": {
      "post": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issueCredential",
        "summary": "Issue a credential in the requested format (dc+sd-jwt or mso_mdoc). Rate-limited per source IP.",
        "parameters": [
          {
            "name": "credential",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "credentialAccessToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "title": "SD-JWT VC",
                    "type": "object",
                    "required": [
                      "format",
                      "vct",
                      "proof"
                    ],
                    "properties": {
                      "format": {
                        "type": "string",
                        "enum": [
                          "dc+sd-jwt"
                        ]
                      },
                      "vct": {
                        "type": "string"
                      },
                      "proof": {
                        "type": "object",
                        "required": [
                          "proof_type"
                        ],
                        "properties": {
                          "proof_type": {
                            "type": "string",
                            "enum": [
                              "jwt",
                              "cwt"
                            ]
                          },
                          "jwt": {
                            "type": "string"
                          },
                          "cwt": {
                            "type": "string",
                            "description": "Base64url COSE_Sign1 (RFC 9052) wrapping a CBOR CWT claim set (RFC 8392). Alternative to `jwt`. Wallets MUST send exactly one of `jwt` or `cwt`; sending both is rejected with `invalid_proof`."
                          }
                        }
                      }
                    }
                  },
                  {
                    "title": "mDoc / ISO 18013-5",
                    "type": "object",
                    "required": [
                      "format",
                      "doctype",
                      "proof"
                    ],
                    "properties": {
                      "format": {
                        "type": "string",
                        "enum": [
                          "mso_mdoc"
                        ]
                      },
                      "doctype": {
                        "type": "string",
                        "enum": [
                          "eu.europa.ec.eudi.pid.1"
                        ],
                        "description": "Only EUDI PID supported today; any other doctype returns unsupported_credential_type."
                      },
                      "proof": {
                        "type": "object",
                        "required": [
                          "proof_type"
                        ],
                        "properties": {
                          "proof_type": {
                            "type": "string",
                            "enum": [
                              "jwt",
                              "cwt"
                            ],
                            "description": "cwt returns unsupported_proof_type today."
                          },
                          "jwt": {
                            "type": "string"
                          },
                          "cwt": {
                            "type": "string",
                            "description": "Base64url COSE_Sign1 (RFC 9052) wrapping a CBOR CWT claim set (RFC 8392). Alternative to `jwt`. Wallets MUST send exactly one of `jwt` or `cwt`; sending both is rejected with `invalid_proof`."
                          }
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credential + format tag. For mso_mdoc, credential is base64url-encoded mDoc bytes (CBOR + COSE_Sign1 issuerAuth).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "credential",
                    "format"
                  ],
                  "properties": {
                    "credential": {
                      "type": "string"
                    },
                    "format": {
                      "type": "string",
                      "enum": [
                        "dc+sd-jwt",
                        "mso_mdoc"
                      ]
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/vci.ashx?create-offer": {
      "post": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "createCredentialOffer",
        "summary": "Create a pre-authorized credential offer for a subject.",
        "parameters": [
          {
            "name": "create-offer",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Offer created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/vci.ashx?offer=<id>": {
      "get": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "getCredentialOffer",
        "summary": "Public wallet-facing offer retrieval (rate-limited per IP).",
        "responses": {
          "200": {
            "description": "Offer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/lotl.ashx?status": {
      "get": {
        "tags": [
          "lotl"
        ],
        "operationId": "lotlStatus",
        "summary": "LOTL cache manifest — freshness, next refresh, anchor count, countries covered.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LotlManifest"
                }
              }
            }
          }
        }
      }
    },
    "/lotl.ashx?anchors": {
      "get": {
        "tags": [
          "lotl"
        ],
        "operationId": "lotlAnchors",
        "summary": "Enumerate trust-anchor fingerprints (optionally by country=XX).",
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/lotl.ashx?anchor=<sha256>": {
      "get": {
        "tags": [
          "lotl"
        ],
        "operationId": "lotlAnchor",
        "summary": "Fetch a specific anchor's PEM cert by SHA-256 fingerprint.",
        "responses": {
          "200": {
            "description": "PEM cert",
            "content": {
              "application/x-pem-file": {
                "schema": {
                  "type": "string"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/lotl.ashx?refresh": {
      "post": {
        "tags": [
          "lotl"
        ],
        "operationId": "lotlRefresh",
        "summary": "Force-refresh the LOTL cache (blocks 20-60s while fetching upstream).",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/rp-cert.ashx?ca": {
      "get": {
        "tags": [
          "rp-cert"
        ],
        "operationId": "rpCertCa",
        "summary": "Retrieve the RP-verifier CA certificate.",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "pem",
                "der"
              ],
              "default": "pem"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/x-pem-file": {
                "schema": {
                  "type": "string"
                }
              },
              "application/pkix-cert": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/rp-cert.ashx?issue": {
      "post": {
        "tags": [
          "rp-cert"
        ],
        "operationId": "rpCertIssue",
        "summary": "Issue an RP verifier certificate.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 90
            }
          },
          {
            "name": "include_key",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Issued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/rp-cert.ashx?list": {
      "get": {
        "tags": [
          "rp-cert"
        ],
        "operationId": "rpCertList",
        "summary": "List issued RP certs (admin).",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/signal.ashx?whitelist=list": {
      "get": {
        "tags": [
          "sip-admin"
        ],
        "operationId": "whitelistList",
        "summary": "Enumerate PSTN whitelist entries for the calling tenant.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/signal.ashx?whitelist=add": {
      "post": {
        "tags": [
          "sip-admin"
        ],
        "operationId": "whitelistAdd",
        "summary": "Add one PSTN number to whitelist. HMAC bucket: whitelist-add|Host|bodyLen.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "number"
                ],
                "properties": {
                  "number": {
                    "type": "string"
                  },
                  "comment": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/signal.ashx?oidc-clients=1": {
      "get": {
        "tags": [
          "sip-admin"
        ],
        "operationId": "oidcClientsList",
        "summary": "List registered OIDC clients (per-tenant).",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/signal.ashx?oidc-clients-save=1": {
      "post": {
        "tags": [
          "sip-admin"
        ],
        "operationId": "oidcClientsSave",
        "summary": "Upsert an OIDC client.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/signal.ashx?oidc-clients-genkey=1": {
      "post": {
        "tags": [
          "sip-admin"
        ],
        "operationId": "oidcClientsGenkey",
        "summary": "Mint and return a new client_secret. Value shown ONCE.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "client_secret": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/signal.ashx?list-vp-events": {
      "get": {
        "tags": [
          "eu-wallet-verifier"
        ],
        "operationId": "listVpEvents",
        "summary": "Verifier audit-log (VP events) for vc-audit.html.",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat.ashx?op=me": {
      "get": {
        "tags": [
          "chat"
        ],
        "operationId": "chatMe",
        "summary": "Return the OIDC-clamped identity of the calling chat user.",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat.ashx?op=list-threads": {
      "get": {
        "tags": [
          "chat"
        ],
        "operationId": "chatListThreads",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat.ashx?op=send": {
      "post": {
        "tags": [
          "chat"
        ],
        "operationId": "chatSend",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "with",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "peer login (DM) OR"
            }
          },
          {
            "name": "groupId",
            "in": "query",
            "schema": {
              "type": "string",
              "description": "group id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "text"
                ],
                "properties": {
                  "text": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/chat.ashx?op=upload": {
      "post": {
        "tags": [
          "chat"
        ],
        "operationId": "chatUpload",
        "summary": "File transfer (multipart/form-data).",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "with",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "groupId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/chat.ashx?op=download": {
      "get": {
        "tags": [
          "chat"
        ],
        "operationId": "chatDownload",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "sha",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/chat-ws.ashx?ticket=<nonce>": {
      "get": {
        "tags": [
          "chat"
        ],
        "operationId": "chatWsUpgrade",
        "summary": "WebSocket upgrade — realtime chat push. Ticket minted via /chat.ashx?op=ws-ticket.",
        "responses": {
          "101": {
            "description": "Switching Protocols (WebSocket)"
          }
        }
      }
    },
    "/chat-widget.ashx?op=probe": {
      "get": {
        "tags": [
          "chat-widget"
        ],
        "operationId": "widgetProbe",
        "summary": "Public 'Chat with us' widget config for the calling origin.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat-widget.ashx?op=start-session": {
      "post": {
        "tags": [
          "chat-widget"
        ],
        "operationId": "widgetStart",
        "summary": "Anonymous visitor session (no auth).",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat-invite.ashx?op=create": {
      "post": {
        "tags": [
          "chat"
        ],
        "operationId": "inviteCreate",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat-invite.ashx?op=verify": {
      "get": {
        "tags": [
          "chat"
        ],
        "operationId": "inviteVerify",
        "summary": "Public verification of a chat invite token (single-use, expiry-clamped).",
        "parameters": [
          {
            "name": "t",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/chat-email.ashx?op=list-threads": {
      "get": {
        "tags": [
          "chat-email"
        ],
        "operationId": "emailListThreads",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/pms.ashx?op=list-threads": {
      "get": {
        "tags": [
          "pms"
        ],
        "operationId": "pmsListThreads",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/pms.ashx?op=reply": {
      "post": {
        "tags": [
          "pms"
        ],
        "operationId": "pmsReply",
        "security": [
          {
            "oidcBearer": []
          },
          {
            "hmacAdmin": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1Root",
        "summary": "v1 REST self-describe (endpoints, build, auth notes).",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api.ashx/v1/calls": {
      "post": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1CreateCall",
        "summary": "Place an outbound AI call.",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone"
                ],
                "properties": {
                  "phone": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "systemPrompt": {
                    "type": "string"
                  },
                  "apiKey": {
                    "type": "string"
                  },
                  "voice": {
                    "type": "string"
                  },
                  "language": {
                    "type": "string"
                  },
                  "maxSeconds": {
                    "type": "integer"
                  },
                  "retries": {
                    "type": "integer"
                  },
                  "scheduleAtUtc": {
                    "type": "string",
                    "format": "date-time"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Call queued",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListCalls",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/api.ashx/v1/calls/{id}": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1GetCall",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/calls/{id}/hangup": {
      "post": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1HangupCall",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/numbers": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListNumbers",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/transcripts": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListTranscripts",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "source",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/transcripts/{callId}": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1GetTranscript",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "callId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/inbound-routes": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListInboundRoutes",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "post": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1CreateInboundRoute",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "Did",
                  "User"
                ],
                "properties": {
                  "Did": {
                    "type": "string"
                  },
                  "FromNumber": {
                    "type": "string"
                  },
                  "User": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created"
          }
        }
      }
    },
    "/api.ashx/v1/outbound-routes": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListOutboundRoutes",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "post": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1CreateOutboundRoute",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "match",
                  "trunkIds"
                ],
                "properties": {
                  "match": {
                    "type": "string"
                  },
                  "trunkIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api.ashx/v1/webhooks": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1ListWebhooks",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK (secrets stripped)"
          }
        }
      }
    },
    "/api.ashx/v1/auditlog": {
      "get": {
        "tags": [
          "v1-rest"
        ],
        "operationId": "v1AuditLog",
        "security": [
          {
            "oidcBearer": []
          }
        ],
        "parameters": [
          {
            "name": "event",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "user",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/sip-tls/health": {
      "get": {
        "tags": [
          "bridge-health"
        ],
        "operationId": "sipTlsHealth",
        "summary": "SIPS listener state + auto-blacklist counters.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/sip-ws/health": {
      "get": {
        "tags": [
          "bridge-health"
        ],
        "operationId": "sipWsHealth",
        "summary": "SIP-over-WSS listener state.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/sfu/health": {
      "get": {
        "tags": [
          "bridge-health"
        ],
        "operationId": "sfuHealth",
        "summary": "SFU module status.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "tags": [
          "well-known"
        ],
        "operationId": "sitemap",
        "responses": {
          "200": {
            "description": "Per-tenant sitemap with Host substitution.",
            "content": {
              "application/xml": {}
            }
          }
        }
      }
    },
    "/robots.txt": {
      "get": {
        "tags": [
          "well-known"
        ],
        "operationId": "robots",
        "responses": {
          "200": {
            "description": "Per-tenant robots.txt.",
            "content": {
              "text/plain": {}
            }
          }
        }
      }
    },
    "/vci.ashx?par": {
      "post": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issuerPar",
        "summary": "Pushed Authorization Request (RFC 9126). Wallet pushes the authorization request out-of-band and receives a one-shot request_uri.",
        "parameters": [
          {
            "name": "par",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "client_id",
                  "response_type",
                  "redirect_uri",
                  "code_challenge",
                  "code_challenge_method"
                ],
                "properties": {
                  "client_id": {
                    "type": "string",
                    "description": "Must be present in App_Data/<tenant>/wallet-clients.json (fallback: aloaha-web-wallet)."
                  },
                  "response_type": {
                    "type": "string",
                    "enum": [
                      "code"
                    ]
                  },
                  "redirect_uri": {
                    "type": "string",
                    "format": "uri"
                  },
                  "code_challenge": {
                    "type": "string",
                    "minLength": 43,
                    "maxLength": 128
                  },
                  "code_challenge_method": {
                    "type": "string",
                    "enum": [
                      "S256"
                    ]
                  },
                  "scope": {
                    "type": "string"
                  },
                  "authorization_details": {
                    "type": "string",
                    "description": "JSON string per RFC 9396."
                  },
                  "state": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "PAR accepted; returns single-use request_uri.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "request_uri",
                    "expires_in"
                  ],
                  "properties": {
                    "request_uri": {
                      "type": "string",
                      "example": "urn:ietf:params:oauth:request_uri:abc123"
                    },
                    "expires_in": {
                      "type": "integer",
                      "example": 60
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request / invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/vci.ashx?authorize": {
      "get": {
        "tags": [
          "eu-wallet-issuer"
        ],
        "operationId": "issuerAuthorize",
        "summary": "OpenID4VCI authorization endpoint. Redirects to OIDC sign-in when unauthenticated, then to the wallet's redirect_uri with a fresh code.",
        "parameters": [
          {
            "name": "authorize",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "request_uri",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Value returned by /vci.ashx?par. When present, all other authorization parameters are ignored."
          },
          {
            "name": "client_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "response_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "code"
              ]
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uri"
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "S256"
              ]
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "authorization_details",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to redirect_uri with ?code=<opaque>&state=<echoed>&iss=<issuer> (RFC 9207).",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request / invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
