AdvisorPPC Admin API

The admin API from AdvisorPPC — 10 operation(s) for admin.

Operations 11

GET /api/admin/engine-mode Get Engine Mode #
PUT /api/admin/engine-mode Set Engine Mode #
GET /api/admin/overview Admin Overview #
POST /api/admin/advisor-mode Set Advisor Mode #
GET /api/admin/tenants List Tenants #
GET /api/admin/staff List Staff #
POST /api/admin/tenants/{tenant_id}/plan Set Tenant Plan #
POST /api/admin/grants/by-email Grant Plan To Email #
GET /api/admin/tenants/{tenant_id}/account Get Tenant Account #
GET /api/admin/support/conversations List Support Conversations #
GET /api/admin/support/conversations/{conversation_id} Get Support Conversation #

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/advisorppc-com:advisorppc-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

advisorppc-com-admin-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: AdvisorPPC Admin API
  version: 0.1.0
tags:
- name: Admin
paths:
  /api/admin/engine-mode:
    get:
      tags:
      - Admin
      summary: Get Engine Mode
      description: 'Report whether advisor format is ON for chat and/or the agent runner.


        Superuser like the PUT: this is PROCESS-GLOBAL configuration, and every

        user owns their personal tenant, so a tenant-role gate would show internal

        engine posture to every customer.'
      operationId: get_engine_mode_api_admin_engine_mode_get
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EngineMode'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    put:
      tags:
      - Admin
      summary: Set Engine Mode
      description: 'Superuser toggle: flip advisor format ON/OFF per call site on this worker.


        SECURITY (F2): this mutates PROCESS-GLOBAL ``settings`` (not tenant data), so

        it is gated on platform superuser, NOT tenant role — every user is owner of

        their personal tenant, so ``require_role("admin")`` here let any logged-in

        user flip the global engine mode.


        Default posture is OFF (single-model Opus path). See the module docstring for

        the durable env-var control and the multi-worker caveat.'
      operationId: set_engine_mode_api_admin_engine_mode_put
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EngineModePatch'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EngineMode'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/overview:
    get:
      tags:
      - Admin
      summary: Admin Overview
      description: 'Aggregate the tenant''s admin snapshot: connector health, usage vs cap,

        billing state, and the Advisor-mode flag. Admin-only; tenant-scoped reads

        run under the RLS GUC. Never returns a secret_ref.'
      operationId: admin_overview_api_admin_overview_get
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Admin Overview Api Admin Overview Get
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/advisor-mode:
    post:
      tags:
      - Admin
      summary: Set Advisor Mode
      description: 'Superuser toggle for Advisor mode (both engine call sites at once).


        SECURITY (F2): maps onto the SAME process-global ``settings`` flags as

        ``PUT /engine-mode``, so it is gated on platform superuser (not tenant role)

        for the identical reason — a personal-tenant owner is not a platform operator.


        DEFAULT OFF; flipping it here changes only the running worker — the durable

        fleet-wide control is the ADVISORPPC_ADVISOR_ENABLED_* env vars.'
      operationId: set_advisor_mode_api_admin_advisor_mode_post
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvisorModeIn'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                title: Response Set Advisor Mode Api Admin Advisor Mode Post
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/tenants:
    get:
      tags:
      - Admin
      summary: List Tenants
      description: 'Platform-wide tenant roster with each tenant''s entitlement.


        ``audience`` picks which workspaces: ``customers`` (the default) leaves out

        workspaces whose members are all staff, ``staff`` lists only those, and

        ``all`` lists both. Every row says which it is in ``isStaff``.


        Cross-tenant by definition, so it runs on the audited superuser bypass path

        rather than pretending to be a tenant-scoped read. Returns no email address

        and no Stripe identifier — an operator picking a plan needs the tenant, its

        tier, and who owns the row, not the customer''s PII.'
      operationId: list_tenants_api_admin_tenants_get
      security:
      - HTTPBearer: []
      parameters:
      - name: q
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            maxLength: 200
          - type: 'null'
          title: Q
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
          default: 0
          title: Offset
      - name: audience
        in: query
        required: false
        schema:
          enum:
          - customers
          - staff
          - all
          type: string
          default: customers
          title: Audience
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRoster'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/staff:
    get:
      tags:
      - Admin
      summary: List Staff
      description: The staff list (``platform_staff``) for the owner console's Team tab.
      operationId: list_staff_api_admin_staff_get
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StaffList'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/tenants/{tenant_id}/plan:
    post:
      tags:
      - Admin
      summary: Set Tenant Plan
      description: 'Grant or revoke a tenant''s entitlement without going through Stripe.


        Refuses outright when Stripe owns the row. That is the one case where

        overriding here would put the product and the payment processor into

        disagreement about what a customer bought — change it in Stripe and let the

        webhook land. Everything written here is ``billing_source=''manual''`` with

        NULL Stripe ids, which the database enforces and the webhook receiver knows

        how to conflict on.'
      operationId: set_tenant_plan_api_admin_tenants__tenant_id__plan_post
      security:
      - HTTPBearer: []
      parameters:
      - name: tenant_id
        in: path
        required: true
        schema:
          type: integer
          title: Tenant Id
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PlanGrantIn'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantPlanRow'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/grants/by-email:
    post:
      tags:
      - Admin
      summary: Grant Plan To Email
      description: 'Grant a plan to an e-mail address, creating the site account if needed.


        Why this exists: this Stripe account also bills the connector runtime

        (mcp.advisorppc.com). Its customers check out on the runtime''s storefront,

        and the site webhook drops their events as a foreign product on purpose,

        so a paying runtime customer who opens advisorppc.com lands on Free. This

        route pre-provisions the site half — a password-less user that Sign in

        with Google links to by e-mail, the personal tenant, and an audited manual

        entitlement — so they arrive on the plan they pay for.


        Same refusal as the tenant route: a row Stripe owns is never overwritten.

        Idempotent: repeating an identical grant reports ``changed=false`` and

        writes no second audit row.'
      operationId: grant_plan_to_email_api_admin_grants_by_email_post
      security:
      - HTTPBearer: []
      parameters:
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EmailGrantIn'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EmailGrantOut'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/tenants/{tenant_id}/account:
    get:
      tags:
      - Admin
      summary: Get Tenant Account
      description: 'One account, in full: owner, plan, connectors, markers, model menu.


        Cross-tenant by definition, so it runs on the audited superuser bypass path

        — the same one the roster and the plan grant use.'
      operationId: get_tenant_account_api_admin_tenants__tenant_id__account_get
      security:
      - HTTPBearer: []
      parameters:
      - name: tenant_id
        in: path
        required: true
        schema:
          type: integer
          title: Tenant Id
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantAccount'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/support/conversations:
    get:
      tags:
      - Admin
      summary: List Support Conversations
      description: 'Most recently active support conversations first.


        ``offset`` pages past the newest ``limit``: ``total`` is returned so the

        operator can see there is more, and without an offset that number would

        be a count of rows nobody could reach.


        ``since`` filters on ``last_message_at`` (when the conversation was last

        ALIVE, not when it started) because "what have people been asking this

        week" is the question this endpoint exists to answer, and a long-running

        thread that started a month ago is part of that answer.'
      operationId: list_support_conversations_api_admin_support_conversations_get
      security:
      - HTTPBearer: []
      parameters:
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 200
          minimum: 1
          default: 50
          title: Limit
      - name: offset
        in: query
        required: false
        schema:
          type: integer
          minimum: 0
          default: 0
          title: Offset
      - name: since
        in: query
        required: false
        schema:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Since
      - name: tenant_id
        in: query
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: Tenant Id
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportConversationList'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /api/admin/support/conversations/{conversation_id}:
    get:
      tags:
      - Admin
      summary: Get Support Conversation
      description: One conversation, every turn, in the order it happened.
      operationId: get_support_conversation_api_admin_support_conversations__conversation_id__get
      security:
      - HTTPBearer: []
      parameters:
      - name: conversation_id
        in: path
        required: true
        schema:
          type: integer
          title: Conversation Id
      - name: X-Tenant-Id
        in: header
        required: false
        schema:
          anyOf:
          - type: integer
          - type: 'null'
          title: X-Tenant-Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SupportConversationDetail'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    TenantPlanRow:
      properties:
        tenantId:
          type: string
          title: Tenantid
        name:
          type: string
          title: Name
        tier:
          type: string
          title: Tier
        status:
          type: string
          title: Status
        billingSource:
          type: string
          title: Billingsource
        members:
          type: integer
          title: Members
        updatedAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Updatedat
        editable:
          type: boolean
          title: Editable
        isStaff:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Isstaff
      additionalProperties: false
      type: object
      required:
      - tenantId
      - name
      - tier
      - status
      - billingSource
      - members
      - editable
      title: TenantPlanRow
      description: One tenant's entitlement as an operator needs to see it.
    SupportConversationDetail:
      properties:
        conversation:
          $ref: '#/components/schemas/SupportConversationRow'
        summary:
          anyOf:
          - type: string
          - type: 'null'
          title: Summary
        messages:
          items:
            $ref: '#/components/schemas/SupportMessageRow'
          type: array
          title: Messages
      additionalProperties: false
      type: object
      required:
      - conversation
      - messages
      title: SupportConversationDetail
    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
    AccountModels:
      properties:
        available:
          items:
            type: string
          type: array
          title: Available
        blocked:
          additionalProperties:
            type: string
          type: object
          title: Blocked
      additionalProperties: false
      type: object
      required:
      - available
      - blocked
      title: AccountModels
      description: Which chat models this account can actually pick, and why not.
    AdvisorModeIn:
      properties:
        enabled:
          type: boolean
          title: Enabled
      additionalProperties: false
      type: object
      required:
      - enabled
      title: AdvisorModeIn
    AccountMember:
      properties:
        userId:
          type: string
          title: Userid
        email:
          type: string
          title: Email
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        role:
          type: string
          title: Role
        isSuperuser:
          type: boolean
          title: Issuperuser
      additionalProperties: false
      type: object
      required:
      - userId
      - email
      - role
      - isSuperuser
      title: AccountMember
    EngineMode:
      properties:
        advisor_enabled_chat:
          type: boolean
          title: Advisor Enabled Chat
        advisor_enabled_runner:
          type: boolean
          title: Advisor Enabled Runner
      additionalProperties: false
      type: object
      required:
      - advisor_enabled_chat
      - advisor_enabled_runner
      title: EngineMode
      description: Current advisor-format posture for both engine call sites.
    EngineModePatch:
      properties:
        advisor_enabled_chat:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Advisor Enabled Chat
        advisor_enabled_runner:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Advisor Enabled Runner
      additionalProperties: false
      type: object
      title: EngineModePatch
      description: 'Partial toggle — omit a field to leave that call site unchanged.


        Reject unknown keys so a typo (e.g. ``advisor_enabled_char``) is a 422, not a

        silent no-op that leaves an operator believing the mode flipped.'
    EmailGrantOut:
      properties:
        tenantId:
          type: string
          title: Tenantid
        name:
          type: string
          title: Name
        tier:
          type: string
          title: Tier
        status:
          type: string
          title: Status
        billingSource:
          type: string
          title: Billingsource
        members:
          type: integer
          title: Members
        updatedAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Updatedat
        editable:
          type: boolean
          title: Editable
        isStaff:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Isstaff
        email:
          type: string
          title: Email
        userId:
          type: string
          title: Userid
        userCreated:
          type: boolean
          title: Usercreated
        tenantCreated:
          type: boolean
          title: Tenantcreated
        changed:
          type: boolean
          title: Changed
        welcomed:
          type: boolean
          title: Welcomed
          default: false
      additionalProperties: false
      type: object
      required:
      - tenantId
      - name
      - tier
      - status
      - billingSource
      - members
      - editable
      - email
      - userId
      - userCreated
      - tenantCreated
      - changed
      title: EmailGrantOut
      description: The granted tenant's plan row plus what the call had to create.
    SupportMessageRow:
      properties:
        id:
          type: string
          title: Id
        role:
          type: string
          title: Role
        content:
          type: string
          title: Content
        createdAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Createdat
        tokenCount:
          anyOf:
          - type: integer
          - type: 'null'
          title: Tokencount
      additionalProperties: false
      type: object
      required:
      - id
      - role
      - content
      title: SupportMessageRow
    EmailGrantIn:
      properties:
        tier:
          type: string
          enum:
          - free
          - pro
          - google
          - gm
          - gmt
          - max
          - agency
          - team
          - enterprise
          title: Tier
        status:
          type: string
          enum:
          - active
          - inactive
          - canceled
          title: Status
          default: active
        reason:
          type: string
          maxLength: 500
          minLength: 3
          title: Reason
        email:
          type: string
          maxLength: 320
          minLength: 3
          title: Email
        name:
          anyOf:
          - type: string
            maxLength: 200
          - type: 'null'
          title: Name
        welcome:
          type: boolean
          title: Welcome
          default: true
      additionalProperties: false
      type: object
      required:
      - tier
      - reason
      - email
      title: EmailGrantIn
      description: 'A plan grant addressed to an e-mail rather than a tenant id.


        The address may have no site account yet: the route creates a password-less

        user (Sign in with Google links by e-mail; forgot-password sets a password),

        their personal tenant, and the manual entitlement in one audited step.

        ``name`` is used only when the user is created.'
    StaffList:
      properties:
        staff:
          items:
            $ref: '#/components/schemas/StaffRow'
          type: array
          title: Staff
        missing:
          items:
            type: string
          type: array
          title: Missing
      additionalProperties: false
      type: object
      required:
      - staff
      - missing
      title: StaffList
    TenantAccount:
      properties:
        tenantId:
          type: string
          title: Tenantid
        name:
          type: string
          title: Name
        slug:
          type: string
          title: Slug
        kind:
          type: string
          title: Kind
        status:
          type: string
          title: Status
        createdAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Createdat
        plan:
          $ref: '#/components/schemas/TenantPlanRow'
        writesEnabled:
          type: boolean
          title: Writesenabled
        gptAllowed:
          type: boolean
          title: Gptallowed
        members:
          items:
            $ref: '#/components/schemas/AccountMember'
          type: array
          title: Members
        connectors:
          items:
            additionalProperties: true
            type: object
          type: array
          title: Connectors
        usageTodayUsd:
          type: number
          title: Usagetodayusd
        models:
          $ref: '#/components/schemas/AccountModels'
      additionalProperties: false
      type: object
      required:
      - tenantId
      - name
      - slug
      - kind
      - status
      - plan
      - writesEnabled
      - gptAllowed
      - members
      - connectors
      - usageTodayUsd
      - models
      title: TenantAccount
      description: Everything an operator or agent needs about one account, in one read.
    StaffRow:
      properties:
        userId:
          type: string
          title: Userid
        email:
          type: string
          title: Email
        name:
          anyOf:
          - type: string
          - type: 'null'
          title: Name
        kind:
          type: string
          title: Kind
        canActAs:
          type: boolean
          title: Canactas
        addedBy:
          anyOf:
          - type: string
          - type: 'null'
          title: Addedby
        addedAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Addedat
      additionalProperties: false
      type: object
      required:
      - userId
      - email
      - kind
      - canActAs
      title: StaffRow
      description: 'One person on the staff list. Staff are not customers, so their own

        address is shown: the owner needs to know who is on the team.'
    SupportConversationRow:
      properties:
        id:
          type: string
          title: Id
        channel:
          type: string
          title: Channel
        startedAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Startedat
        lastMessageAt:
          anyOf:
          - type: string
          - type: 'null'
          title: Lastmessageat
        tenantId:
          anyOf:
          - type: string
          - type: 'null'
          title: Tenantid
        tenantName:
          anyOf:
          - type: string
          - type: 'null'
          title: Tenantname
        userEmail:
          anyOf:
          - type: string
          - type: 'null'
          title: Useremail
        firstUserLine:
          anyOf:
          - type: string
          - type: 'null'
          title: Firstuserline
        messageCount:
          type: integer
          title: Messagecount
        hasSummary:
          type: boolean
          title: Hassummary
      additionalProperties: false
      type: object
      required:
      - id
      - channel
      - messageCount
      - hasSummary
      title: SupportConversationRow
      description: 'One conversation as the list needs it: who, when, and the opening line.'
    SupportConversationList:
      properties:
        conversations:
          items:
            $ref: '#/components/schemas/SupportConversationRow'
          type: array
          title: Conversations
        total:
          type: integer
          title: Total
        limit:
          type: integer
          title: Limit
        offset:
          type: integer
          title: Offset
      additionalProperties: false
      type: object
      required:
      - conversations
      - total
      - limit
      - offset
      title: SupportConversationList
    TenantRoster:
      properties:
        tenants:
          items:
            $ref: '#/components/schemas/TenantPlanRow'
          type: array
          title: Tenants
        total:
          type: integer
          title: Total
        limit:
          type: integer
          title: Limit
        offset:
          type: integer
          title: Offset
        audience:
          type: string
          title: Audience
          default: customers
      additionalProperties: false
      type: object
      required:
      - tenants
      - total
      - limit
      - offset
      title: TenantRoster
    PlanGrantIn:
      properties:
        tier:
          type: string
          enum:
          - free
          - pro
          - google
          - gm
          - gmt
          - max
          - agency
          - team
          - enterprise
          title: Tier
        status:
          type: string
          enum:
          - active
          - inactive
          - canceled
          title: Status
          default: active
        reason:
          type: string
          maxLength: 500
          minLength: 3
          title: Reason
      additionalProperties: false
      type: object
      required:
      - tier
      - reason
      title: PlanGrantIn
      description: A deliberate, attributed plan change. ``reason`` is not optional.
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer