{
  "openapi": "3.1.0",
  "info": {
    "title": "MetaEco 应用服务端 API",
    "version": "6.0.0"
  },
  "servers": [
    {
      "url": "{platformOrigin}",
      "description": "导入后填写实际 API 入口；文档域名不承载 API",
      "variables": {
        "platformOrigin": {
          "default": "https://api.example.invalid",
          "description": "替换为当前应用分配的 API 网关，示例域名不可访问"
        }
      }
    }
  ],
  "paths": {
    "/miniapp/v1/apps/{app_id}/phone-number": {
      "post": {
        "summary": "应用后端兑换手机号",
        "description": "手机号独立于scope和登录会话。code为5分钟一次性凭证，绑定AppID与当前号码验证证明；模拟号码仅允许Dev/Test白名单应用testing版本及有效测试资格，签发和兑换均检查。宿主确认只能在原生用户同意后执行。请求不接受目标用户/号码或额外query参数。服务未配置时失败关闭。",
        "tags": [
          "runtime"
        ],
        "security": [
          {
            "serviceCredential": []
          }
        ],
        "operationId": "exchangePhoneNumber",
        "parameters": [
          {
            "$ref": "#/components/parameters/AppID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhoneCodeExchange"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/PhoneExchanged"
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/RuntimeUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/miniapp/v1/apps/{app_id}/runtime/sessions/exchange": {
      "post": {
        "summary": "交换运行时会话",
        "description": "应用后端持服务凭据兑换一次性 code，获得 AppID 作用域 openid 和仅后端保存的 token。run_instance_id 必填于请求体，旧客户端若同时传实例 Header，必须与请求体一致。业务登录态由应用后端建立，平台 token 禁止返回 JS。",
        "tags": [
          "runtime"
        ],
        "security": [
          {
            "serviceCredential": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AppID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionExchangeRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Session token. The token is returned only here.",
            "headers": {
              "X-Request-ID": {
                "$ref": "#/components/headers/RequestID"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionExchangeResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/RuntimeUnauthorized"
          }
        }
      }
    },
    "/miniapp/v1/apps/{app_id}/runtime/sessions/validate": {
      "post": {
        "summary": "校验运行时会话",
        "description": "校验当前运行时会话是否有效且未被吊销。",
        "tags": [
          "runtime"
        ],
        "security": [
          {
            "serviceCredential": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AppID"
          },
          {
            "$ref": "#/components/parameters/RunInstance"
          },
          {
            "$ref": "#/components/parameters/Session"
          }
        ],
        "responses": {
          "200": {
            "description": "Valid session.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/RuntimeUnauthorized"
          }
        }
      }
    },
    "/miniapp/v1/apps/{app_id}/runtime/sessions/revoke": {
      "post": {
        "summary": "吊销运行时会话",
        "description": "主动吊销当前小程序运行时会话。",
        "tags": [
          "runtime"
        ],
        "security": [
          {
            "serviceCredential": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/AppID"
          },
          {
            "$ref": "#/components/parameters/RunInstance"
          },
          {
            "$ref": "#/components/parameters/Session"
          }
        ],
        "responses": {
          "204": {
            "description": "Session revoked."
          },
          "401": {
            "$ref": "#/components/responses/RuntimeUnauthorized"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "serviceCredential": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "MiniAppServiceCredential",
        "description": "小程序运行时和内部服务调用使用的短期服务凭据。"
      }
    },
    "parameters": {
      "AppID": {
        "name": "app_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9_-]{2,63}$"
        }
      },
      "RunInstance": {
        "name": "X-MiniApp-Run-Instance",
        "in": "header",
        "required": true,
        "description": "当前小程序运行实例 ID，用于隔离会话和撤销范围。",
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128
        }
      },
      "Session": {
        "name": "X-MiniApp-Session",
        "in": "header",
        "required": true,
        "description": "会话交换成功后返回的运行时会话令牌。",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 4096
        }
      }
    },
    "schemas": {
      "PhoneCodeExchange": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^mp_phone_[a-f0-9]{64}$"
          }
        }
      },
      "SuccessCode": {
        "type": "string",
        "const": "miniapp_success",
        "description": "请求成功时返回的稳定业务码。"
      },
      "ErrorResponse": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "reason": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "SessionExchangeRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code",
          "run_instance_id"
        ],
        "properties": {
          "code": {
            "type": "string",
            "minLength": 1
          },
          "run_instance_id": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128
          }
        }
      },
      "SessionExchangeResponse": {
        "type": "object",
        "required": [
          "code",
          "data"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/SuccessCode"
          },
          "data": {
            "type": "object",
            "required": [
              "session",
              "token"
            ],
            "properties": {
              "session": {
                "$ref": "#/components/schemas/Session"
              },
              "token": {
                "type": "string"
              }
            }
          }
        }
      },
      "Session": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "app_id",
          "version",
          "openid",
          "run_instance_id",
          "issued_at",
          "expires_at"
        ],
        "properties": {
          "app_id": {
            "type": "string"
          },
          "version": {
            "$ref": "#/components/schemas/SemVer"
          },
          "openid": {
            "type": "string",
            "pattern": "^oid_[0-9a-f]{48}$",
            "description": "本应用内稳定的用户标识；不同应用互不关联。"
          },
          "run_instance_id": {
            "type": "string"
          },
          "issued_at": {
            "type": "string",
            "format": "date-time"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SemVer": {
        "type": "string",
        "pattern": "^(0|[1-9][0-9]*)\\\\.(0|[1-9][0-9]*)\\\\.(0|[1-9][0-9]*)(?:-(?:0|[1-9][0-9]*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*)(?:\\\\.(?:0|[1-9][0-9]*|[0-9A-Za-z-]*[A-Za-z-][0-9A-Za-z-]*))*)?$"
      },
      "SessionResponse": {
        "type": "object",
        "required": [
          "code",
          "data"
        ],
        "properties": {
          "code": {
            "$ref": "#/components/schemas/SuccessCode"
          },
          "data": {
            "$ref": "#/components/schemas/Session"
          }
        }
      }
    },
    "responses": {
      "PhoneExchanged": {
        "description": "手机号操作成功；mock仅用于测试。",
        "headers": {
          "Cache-Control": {
            "schema": {
              "type": "string",
              "const": "no-store"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "required": [
                "code",
                "data"
              ],
              "properties": {
                "code": {
                  "$ref": "#/components/schemas/SuccessCode"
                },
                "data": {
                  "type": "object",
                  "required": [
                    "phone_info",
                    "verification_method"
                  ],
                  "properties": {
                    "phone_info": {
                      "type": "object",
                      "required": [
                        "phoneNumber",
                        "purePhoneNumber",
                        "countryCode"
                      ],
                      "properties": {
                        "phoneNumber": {
                          "type": "string"
                        },
                        "purePhoneNumber": {
                          "type": "string"
                        },
                        "countryCode": {
                          "type": "string"
                        }
                      }
                    },
                    "verification_method": {
                      "type": "string",
                      "enum": [
                        "sms",
                        "mock"
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      },
      "InvalidRequest": {
        "description": "请求参数无效。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "RuntimeUnauthorized": {
        "description": "服务凭据或运行时会话无效。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "权限不足或能力调用被拒绝。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "依赖的适配器或存储不可用。",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    },
    "headers": {
      "RequestID": {
        "description": "请求追踪 ID，用于关联客户端、网关和服务端日志。",
        "schema": {
          "type": "string",
          "maxLength": 128
        }
      }
    }
  }
}