twtapi-com Admin API

The Admin API from twtapi-com — 18 operation(s) for admin.

Operations 20

GET /admin/users List Users #
GET /admin/users/{user_id} Get User #
GET /admin/users/{user_id}/risk Get User Risk #
POST /admin/users/{user_id}/credits Adjust Credits #
POST /admin/users/{user_id}/status Update Status #
POST /admin/users/{user_id}/limits Update Limits #
POST /admin/users/{user_id}/plan Update User Plan #
GET /admin/orders List Orders #
GET /admin/orders/{order_id} Get Order #
GET /admin/logs Get Call Logs #
GET /admin/users/{user_id}/activity Get User Activity #
GET /admin/revenue Revenue Stats #
GET /admin/stats Global Stats #
GET /admin/growth-funnel Growth Funnel #
GET /admin/rapidapi-quota Rapidapi Quota #
GET /admin/leak-audit Leak Audit #
GET /admin/plans Get Plans #
POST /admin/plans Create Plan #
PUT /admin/plans/{plan_id} Update Plan #
DELETE /admin/plans/{plan_id} Delete Plan #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/twtapi-com:twtapi-com-admin-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

twtapi-com-admin-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: TwtAPI Backend Admin API
  description: API proxy & billing platform for Twitter/RapidAPI
  version: 0.1.0
tags:
- name: Admin
paths:
  /admin/users:
    get:
      summary: List Users
      description: '用户列表(分页),后台首页用。


        参数:

        page/size: 分页,size 上限 100,避免后台误传大 size 拖垮 DB。

        email: 支持全量邮箱(含 @ 走等值命中索引)和子串(走 ilike 模糊匹配)。


        返回:{total, page, size, items};items 里同时给出 snake_case 与 camelCase

        两种字段名(前端历史命名不统一,属于对旧客户端的兼容,不要删任一份)。


        性能说明:一次请求内对所有 user 做固定次数的批量查询(调用次数、累计消费、

        注册 IP、风控画像各一次),不存在逐用户的 N+1。'
      operationId: list_users_admin_users_get
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Size
      - name: email
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Filter by full email or email substring
          title: Email
        description: Filter by full email or email substring
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}:
    get:
      summary: Get User
      description: '单个用户详情。


        include_risk 控制是否附带风控明细(该计算有一定开销,按需关闭)。


        副作用:rate_limit_service.get_user_usage 内部可能读 Redis 甚至回算 DB。

        用户不存在时返回 404 错误体(HTTP 状态码仍是 200,由统一响应包装处理)。'
      operationId: get_user_admin_users__user_id__get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      - name: include_risk
        in: query
        required: false
        schema:
          type: boolean
          default: true
          title: Include Risk
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/risk:
    get:
      summary: Get User Risk
      description: '只读该用户的风控详情(命中缓存的用户信息 + 风控画像)。


        用户不存在时返回 404 错误体;无写库、无外部请求。'
      operationId: get_user_risk_admin_users__user_id__risk_get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/credits:
    post:
      summary: Adjust Credits
      description: '人工增减积分(amount 正数=加、负数=扣)。


        副作用(三处,顺序重要):

        1. 改 MySQL 并写一条 CreditLog(credit_service 内部用 SELECT ... FOR UPDATE

        行锁,本身就在事务里,并会 commit);

        2. 清该用户的鉴权缓存 + C 端看板缓存,让前台立刻看到新余额;

        3. 若开启 CREDIT_USE_REDIS,再把增量同步到 Redis 余额。


        一致性取舍:第 3 步失败(Redis 不可用)只记异常日志、不抛错——此时

        MySQL 已是权威数据,Redis 只是加速层,失败会由后续读路径回源修正;

        反过来若抛错会让运营以为"操作失败"而重复操作,造成重复加减。


        异常:金额/用户不存在等业务错误被 credit_service 抛成 ValueError,

        这里转成 400 返回。'
      operationId: adjust_credits_admin_users__user_id__credits_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminCreditAdjust'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/status:
    post:
      summary: Update Status
      description: '冻结/解冻用户(只允许 active 与 frozen 两种状态)。


        白名单校验必须放在最前面:status 会直接写进 User.status 并被鉴权路径读取,

        传入未定义的值会让用户既不算冻结也不算正常,属于非法状态防护。


        副作用:写库(commit)+ 清该用户鉴权缓存(缓存里的 status 决定能否调用,

        不清缓存会导致冻结不立即生效)。'
      operationId: update_status_admin_users__user_id__status_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminStatusUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/limits:
    post:
      summary: Update Limits
      description: '单独调整用户的两级限流(每秒/每小时请求数)。


        用 None 判断而非真值判断:显式的 0 是合法值(表示"不限速/封禁"),

        若写成 `if body.rate_limit_per_second:` 会导致传 0 被静默忽略。


        副作用:写库(commit)+ 清该用户鉴权缓存(限流值缓存在其中)。'
      operationId: update_limits_admin_users__user_id__limits_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminLimitUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/plan:
    post:
      summary: Update User Plan
      description: '把用户切换到指定 API 套餐(同时覆盖限流值、可选重置积分、刷新到期时间)。


        参数:

        body.plan_id: 目标套餐,必须是 plan_type=''api'' 且 is_active 的套餐,

        否则 404,避免把用户挂到已下架/非 API 套餐上。

        body.reset_credits: 是否把积分重置为套餐额度(按 monthly_limit 换算)。

        body.validity_period: 有效期档位,未传则用套餐自带档位,再兜底 "1m"。


        副作用:一次事务内改 User + 追加 CreditLog 后 commit;随后清用户鉴权缓存和

        C 端看板缓存,最后(如需)把积分增量同步进 Redis。Redis 失败只记日志不抛错,

        与 adjust_credits 的取舍一致:MySQL 为准,Redis 是加速层。


        事务边界:所有字段改动都攒到同一次 commit,中间不落库;因此下面的

        validity_period 校验失败直接 return 时,本次会话里的改动不会被提交(被丢弃)。'
      operationId: update_user_plan_admin_users__user_id__plan_post
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminUserPlanUpdate'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/orders:
    get:
      summary: List Orders
      description: '订单列表(分页,可按状态过滤),按 id 倒序 = 最新在前。


        status 过滤逻辑收在 _apply_order_filters,保证 total 与列表口径一致。

        用户邮箱用一次 IN 查询批量取回再在内存里映射,避免逐单查 User(N+1)。

        订单可能没有 user_id(游客单/后台代下单),所以先过滤 falsy 再 IN。'
      operationId: list_orders_admin_orders_get
      parameters:
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 20
          title: Size
      - name: status
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: pending | paid | cancelled
          title: Status
        description: pending | paid | cancelled
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/orders/{order_id}:
    get:
      summary: Get Order
      description: '订单详情。


        lang 会被 get_effective_lang 覆盖:优先取请求头/query 的语言,仅在没有

        任何语言信息时才用函数默认值,因此不能把这里的默认值当作"已定语言"。


        status_reason 由 infer_order_status_reason 反推,包含对历史遗留失败单

        (如 EasyGo 0 元单)的兼容推断,见 app/services/order_status_reason.py。


        副作用:只读。订单不存在返回 404 错误体。'
      operationId: get_order_admin_orders__order_id__get
      parameters:
      - name: order_id
        in: path
        required: true
        schema:
          type: integer
          title: Order Id
      - name: lang
        in: query
        required: false
        schema:
          type: string
          default: zh
          title: Lang
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/logs:
    get:
      summary: Get Call Logs
      description: '全局调用日志(分页),可按 user_id 过滤。


        注意 user_id 用 `is not None` 判断而非真值判断:这样"未传参(不过滤)"和

        "传了 0"能区分开,避免将来引入合法 id 为 0 的场景时静默失效。


        性能取舍:查询与计数分成两条 SQL;大表上 count(*) 成本不低,但后台需要

        真实总数。列表按 id 倒序,走主键即可,无需额外索引。


        脱敏:request_params 走 _public_params,密钥字段不会出现在响应里。'
      operationId: get_call_logs_admin_logs_get
      parameters:
      - name: user_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: User Id
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Size
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/users/{user_id}/activity:
    get:
      summary: Get User Activity
      description: '单个用户的活动视图:最近调用明细 + 端点/搜索词 Top10。


        与 /logs 的区别:这里会把数字 user_id 还原成 @用户名,并做聚合统计。


        关键取舍:用户名只读缓存(_resolve_cached_twitter_usernames),不发上游请求,

        防止后台页面被上游 RT 拖住;冷缓存时优先展示数字 id。


        聚合口径:先对原始兴趣点做统计、再逐条做用户名替换。替换是一一对应的

        (同一 id 只会替换成同一个 @name),所以不会把同一次搜索拆成两条。

        传给替换函数的是 dict(...) 浅拷贝,正是为了不污染 raw_interests。


        副作用:只读(User 存在性校验 + 日志查询 + Redis 读)。'
      operationId: get_user_activity_admin_users__user_id__activity_get
      parameters:
      - name: user_id
        in: path
        required: true
        schema:
          type: integer
          title: User Id
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 100
          minimum: 1
          default: 30
          title: Size
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/revenue:
    get:
      summary: Revenue Stats
      description: 营收看板接口,参数经 pattern 正则限定,非法值在进入业务逻辑前就被 FastAPI 拒掉。
      operationId: revenue_stats_admin_revenue_get
      parameters:
      - name: view
        in: query
        required: false
        schema:
          type: string
          pattern: ^(day|month)$
          default: day
          title: View
      - name: include_free
        in: query
        required: false
        schema:
          type: boolean
          default: true
          title: Include Free
      - name: include_empty
        in: query
        required: false
        schema:
          type: boolean
          default: false
          title: Include Empty
      - name: billing_mode
        in: query
        required: false
        schema:
          type: string
          pattern: ^(all|one_time|subscription)$
          default: all
          title: Billing Mode
      - name: page
        in: query
        required: false
        schema:
          type: integer
          minimum: 1
          default: 1
          title: Page
      - name: size
        in: query
        required: false
        schema:
          type: integer
          maximum: 366
          minimum: 1
          default: 31
          title: Size
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/stats:
    get:
      summary: Global Stats
      description: 'Aggregate stats for the admin dashboard. Cached for 5 minutes.


        缓存 5 分钟是刻意的:统计口径不要求实时,而这个接口内部有十几条 count,

        后台首页频繁刷新时靠缓存顶住。'
      operationId: global_stats_admin_stats_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
      tags:
      - Admin
  /admin/growth-funnel:
    get:
      summary: Growth Funnel
      description: 'Return user-level activation, retention, and first-payment cohorts.


        具体聚合逻辑在 growth_service.build_growth_funnel,本路由只做参数校验与

        统一响应包装。days 上限 180 用于限制大范围扫描的开销。'
      operationId: growth_funnel_admin_growth_funnel_get
      parameters:
      - name: days
        in: query
        required: false
        schema:
          type: integer
          maximum: 180
          minimum: 1
          default: 30
          title: Days
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/rapidapi-quota:
    get:
      summary: Rapidapi Quota
      description: '返回最近一次写入的 RapidAPI 套餐配额信息(每次真实代理请求会覆盖写入)。


        数据源是 Redis 里的单条快照(写入方在网关侧),所以这里只反映"最后一次

        代理请求发生时"的配额,长时间没有流量就不会更新。


        返回 None 的三种情况(都属于"无可用数据",不是错误):

        缓存不存在/不是 dict、缺 limit 或 remaining、值无法转 int。


        副作用:只读 Redis。usage_percent 用 limit > 0 守卫除法,避免除零。'
      operationId: rapidapi_quota_admin_rapidapi_quota_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
      tags:
      - Admin
  /admin/leak-audit:
    get:
      summary: Leak Audit
      description: '查看网关成功响应中的供应商关键词审计事件(Redis 列表聚合)。


        用途:排查上游响应里是否泄露了供应商(如 RapidAPI 供应商名)关键词。


        参数:

        hours: 时间窗口,1~168 小时(上限一周)。

        limit: 最多扫描 Redis 列表的前 N 条(列表由写入方 LPUSH 最新在前)。


        返回:原始事件列表 items + 按 path 聚合的 by_endpoint(按命中数倒序)。


        数据不可信是这里最大的特点:Redis 里的 JSON 可能被截断、字段类型可能漂移,

        因此每一条都做了 try/except 与类型收敛,脏数据一律跳过或降级为 0,

        绝不让后台页面 500。


        副作用:只读 Redis。注意这里不写回、不清理列表(列表长度由写入方控制)。'
      operationId: leak_audit_admin_leak_audit_get
      parameters:
      - name: hours
        in: query
        required: false
        schema:
          type: integer
          maximum: 168
          minimum: 1
          default: 24
          title: Hours
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 2000
          minimum: 1
          default: 200
          title: Limit
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/plans:
    get:
      summary: Get Plans
      description: 'Return all plans from the plans table.


        这里返回**所有**套餐(含已下架的 is_active=False),与 C 端公开接口只返回

        生效套餐的口径不同:后台需要看到下架套餐才能重新启用。

        plan_type 为空则不过滤。'
      operationId: get_plans_admin_plans_get
      parameters:
      - name: plan_type
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Plan Type
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
    post:
      summary: Create Plan
      description: 'Create a new plan.


        注意:credits 不接受请求传入,而是由 monthly_limit 反推(见

        internal_plan_credits),保证"额度"与"积分"不会被人为配歪。

        features 以 JSON 文本落库,ensure_ascii=False 是为了让中文特性名在库里可读。


        副作用:写库 + 清套餐缓存(含 C 端公开套餐列表)。'
      operationId: create_plan_admin_plans_post
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminPlanUpsert'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
  /admin/plans/{plan_id}:
    put:
      summary: Update Plan
      description: 'Update an existing plan.


        与创建的区别:credits 的换算带 fallback_credits=plan.credits,即当套餐不是

        API 类型(不参与反推)时保留原有积分值,避免改个名字就把积分清零。


        改完会调 _sync_plan_user_entitlements 给在期用户补差,让新额度立刻生效;

        返回体里带 synced_users 告知运营影响了多少人。


        副作用:写库 + 给用户补积分(会写 CreditLog)+ 清套餐缓存与相关用户缓存。

        顺序上先 commit 套餐本身、再补用户权益,保证套餐改动不会被后面的失败带崩。'
      operationId: update_plan_admin_plans__plan_id__put
      parameters:
      - name: plan_id
        in: path
        required: true
        schema:
          type: integer
          title: Plan Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdminPlanUpsert'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
    delete:
      summary: Delete Plan
      description: '删除套餐。默认软删(is_active=False),hard=True 才是物理删除。


        默认软删的原因:订单/用户可能仍引用该套餐 id,物理删除会让历史订单的

        套餐信息失去关联、也让 _load_plan_map 之外的地方出现悬空引用。


        注意:硬删不会清理 User.current_plan_id 的引用,也不会给受影响用户补差,

        属于"确需清理脏数据"时才用的操作。


        副作用:写库(硬删=DELETE,软删=UPDATE)+ 清套餐缓存。'
      operationId: delete_plan_admin_plans__plan_id__delete
      parameters:
      - name: plan_id
        in: path
        required: true
        schema:
          type: integer
          title: Plan Id
      - name: hard
        in: query
        required: false
        schema:
          type: boolean
          description: True = permanently delete, False = soft-delete (set is_active=False)
          default: false
          title: Hard
        description: True = permanently delete, False = soft-delete (set is_active=False)
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema: {}
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      tags:
      - Admin
components:
  schemas:
    AdminCreditAdjust:
      properties:
        amount:
          type: number
          title: Amount
        description:
          type: string
          title: Description
          default: ''
      type: object
      required:
      - amount
      title: AdminCreditAdjust
      description: 管理员手动调整用户余额。amount 可正可负,会写入 CreditLog 审计。
    AdminPlanUpsert:
      properties:
        plan_type:
          type: string
          title: Plan Type
          default: api
        name:
          type: string
          title: Name
        price:
          type: number
          title: Price
          default: 0
        subscription_price:
          type: number
          title: Subscription Price
          default: 0
        currency:
          type: string
          title: Currency
          default: usd
        monthly_limit:
          type: integer
          title: Monthly Limit
          default: 0
        rate_limit_per_second:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rate Limit Per Second
        rate_limit_per_hour:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rate Limit Per Hour
        features:
          items:
            type: string
          type: array
          title: Features
          default: []
        is_popular:
          type: boolean
          title: Is Popular
          default: false
        button_text:
          type: string
          title: Button Text
          default: 立即开始
        button_style:
          type: string
          title: Button Style
          default: blue
        billing_mode:
          type: string
          title: Billing Mode
          default: one_time
        trial_period:
          anyOf:
          - type: string
          - type: 'null'
          title: Trial Period
        validity_period:
          type: string
          title: Validity Period
          default: 1m
        overage_price_per_call:
          anyOf:
          - type: number
          - type: 'null'
          title: Overage Price Per Call
        sort_order:
          type: integer
          title: Sort Order
          default: 0
        is_active:
          type: boolean
          title: Is Active
          default: true
      type: object
      required:
      - name
      title: AdminPlanUpsert
      description: 'Create or update a plan row.


        中文:后台套餐的新增/编辑入参(同一模型服务两个动作)。

        注意这里没有 ``id``:更新时由路径参数指定目标,新增时不带 id。

        字段与 models.Plan 一一对应,改动需两侧同步。'
    AdminStatusUpdate:
      properties:
        status:
          type: string
          title: Status
      type: object
      required:
      - status
      title: AdminStatusUpdate
      description: 管理员冻结/解冻账户。改完必须失效用户缓存,否则最长 5 分钟不生效。
    AdminLimitUpdate:
      properties:
        rate_limit_per_second:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rate Limit Per Second
        rate_limit_per_hour:
          anyOf:
          - type: integer
          - type: 'null'
          title: Rate Limit Per Hour
      type: object
      title: AdminLimitUpdate
      description: 管理员覆盖用户级限流。传 None 表示清除覆盖、回退到套餐默认值。
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    AdminUserPlanUpdate:
      properties:
        plan_id:
          type: integer
          title: Plan Id
        reset_credits:
          type: boolean
          title: Reset Credits
          default: true
        validity_period:
          anyOf:
          - type: string
          - type: 'null'
          title: Validity Period
      type: object
      required:
      - plan_id
      title: AdminUserPlanUpdate
      description: '管理员为用户换套餐。


        reset_credits=True 时会按新套餐重置剩余额度(默认行为,符合「买套餐」直觉);

        请按需关闭以免抹掉用户已充值购买的余额。

        validity_period 为空表示沿用套餐自身的有效期。'
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError