openapi: 3.1.0
info:
  title: BerryBox Management API
  version: 0.2.0
  description: |
    Core Management API contract for health, team identity, scoped API keys
    and recorded finance. CI jobs, current wallet, runner settings and budget
    operations are documented separately at /docs/api-reference/ci.
    Keys are bound to a team and checked against current membership and role.
  contact:
    name: Strawberry Labs LLC
    url: https://berrybox.io
servers:
  - url: https://berrybox.io
    description: BerryBox production origin
security:
  - ManagementKey: []
tags:
  - name: Health
    description: Process liveness outside the API prefix.
  - name: Teams
    description: The team bound to the authenticated management key.
  - name: Management keys
    description: Scoped, team-bound credentials; current membership and role also apply.
  - name: Recorded finance
    description: Exact recorded usage and accounting snapshots.
paths:
  /health:
    get:
      operationId: getHealth
      tags: [Health]
      summary: Check API health
      description: Returns process liveness. This does not verify runtime or provider readiness.
      security: []
      responses:
        '200':
          description: The API process is responding.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [ok, type]
                properties:
                  ok:
                    type: boolean
                    const: true
                  type:
                    type: string
                    const: health.ok
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /api/management/v1/team:
    get:
      operationId: getCurrentTeam
      tags: [Teams]
      summary: Read the current team
      description: |
        Requires teams:read. The team is resolved from the key's stored team
        binding and the creator's current membership; there is no team override.
      responses:
        '200':
          description: The authenticated team and the creator's current role.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [team]
                properties:
                  team:
                    $ref: '#/components/schemas/TeamIdentity'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /api/management/v1/api-keys:
    get:
      operationId: listManagementKeys
      tags: [Management keys]
      summary: List management keys
      description: |
        Requires keys:read. Owners and admins can list active keys in their team.
        Members see only their own active keys. Revoked keys and secrets are omitted.
      responses:
        '200':
          description: Visible keys, newest first.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [ok, type, apiKeys]
                properties:
                  ok:
                    type: boolean
                    const: true
                  type:
                    type: string
                    const: api_key.list
                  apiKeys:
                    type: array
                    items:
                      $ref: '#/components/schemas/ManagementKeyMetadata'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      operationId: createManagementKey
      tags: [Management keys]
      summary: Create a management key
      description: |
        Requires keys:write. Requested scopes must be a subset of both the caller's
        key scopes and current role permissions. Members create their own keys.
        Billing-only members cannot manage keys. Store the returned secret securely;
        subsequent list operations cannot retrieve it.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                name:
                  type: string
                  maxLength: 120
                  default: API key
                expiresInSeconds:
                  type: integer
                  minimum: 60
                  maximum: 2592000
                  default: 86400
                scopes:
                  type: array
                  description: |
                    When omitted, the service grants the permitted subset of
                    teams:read and ci:read. Current membership and role still apply.
                  items:
                    $ref: '#/components/schemas/ManagementScope'
      responses:
        '201':
          description: The new key and its one-time secret.
          headers:
            Cache-Control:
              $ref: '#/components/headers/NoStore'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [ok, type, apiKey, secret]
                properties:
                  ok:
                    type: boolean
                    const: true
                  type:
                    type: string
                    const: api_key.created
                  apiKey:
                    $ref: '#/components/schemas/ManagementKeyMetadata'
                  secret:
                    $ref: '#/components/schemas/ManagementKeySecret'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /api/management/v1/api-keys/{apiKeyId}/rotate:
    parameters:
      - $ref: '#/components/parameters/ApiKeyId'
    post:
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      operationId: rotateManagementKey
      tags: [Management keys]
      summary: Rotate a management key
      description: |
        Requires keys:write and permission to manage this key. The existing secret
        stops working immediately. The key ID and scopes remain unchanged.
        Rotation is forbidden when the target key has scopes beyond the caller's
        current permissions.
      responses:
        '201':
          description: Updated key metadata and its replacement one-time secret.
          headers:
            Cache-Control:
              $ref: '#/components/headers/NoStore'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [ok, type, apiKey, secret]
                properties:
                  ok:
                    type: boolean
                    const: true
                  type:
                    type: string
                    const: api_key.rotated
                  apiKey:
                    $ref: '#/components/schemas/ManagementKeyMetadata'
                  secret:
                    $ref: '#/components/schemas/ManagementKeySecret'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /api/management/v1/api-keys/{apiKeyId}:
    parameters:
      - $ref: '#/components/parameters/ApiKeyId'
    delete:
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      operationId: revokeManagementKey
      tags: [Management keys]
      summary: Revoke a management key
      description: |
        Requires keys:write and permission to manage this key. Revocation
        invalidates its secret. A missing, already revoked, or inaccessible key
        is not found.
      responses:
        '200':
          description: The key has been revoked.
          content:
            application/json:
              schema:
                type: object
                additionalProperties: false
                required: [ok, type, id]
                properties:
                  ok:
                    type: boolean
                    const: true
                  type:
                    type: string
                    const: api_key.revoked
                  id:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /api/management/v1/usage:
    get:
      operationId: getRecordedUsage
      tags:
        - Recorded finance
      summary: Read verified daily usage snapshots
      description: Requires explicit billing:read and the key creator’s current owner, admin or billing
        role. Team and account come only from the stored key binding. The exact key generation/scope
        and membership are checked again in one read-only repeatable snapshot. No caller-supplied team
        override is supported. Read work has an 8-second transport deadline after the independent
        key/rate guards. Missing or current-day usage remains unavailable; producer completeness is
        unverified. No provider IDs, raw usage attributes or private ledger metadata are returned.
      parameters:
        - in: query
          name: from
          required: true
          description: Inclusive UTC day.
          schema:
            type: string
            format: date
            pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
        - in: query
          name: to
          required: true
          description: Exclusive UTC day; at most tomorrow. Range must contain 1–366 days.
          schema:
            type: string
            format: date
            pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
        - in: query
          name: product
          required: false
          schema:
            type: string
            enum:
              - all
              - sandbox
              - ci
            default: all
      responses:
        "200":
          description: Recorded, tenant-scoped accounting. For current CI wallet and runtime controls, use /api/management/v1/ci endpoints.
          headers:
            Cache-Control:
              schema:
                type: string
                const: private, no-store
              description: Private financial responses must not be cached.
            Vary:
              schema:
                type: string
                const: Authorization, Origin
              description: Credential and origin response partitioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordedUsage"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "422":
          description: Choose a narrower date range; raw rows, groups or response bytes exceed the bounded
            read limits.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementError"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "503":
          description: The recorded-finance source is unavailable, inconsistent or past its bounded read deadline.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementError"
  /api/management/v1/billing:
    get:
      operationId: getRecordedBilling
      tags:
        - Recorded finance
      summary: Read recorded billing accounting
      description: Requires explicit billing:read and the key creator’s current owner, admin or billing
        role. Team and account come only from the stored key binding. The exact key generation/scope
        and membership are checked again in one read-only repeatable snapshot. No caller-supplied team
        override is supported. Read work has an 8-second transport deadline after the independent
        key/rate guards. Missing or current-day usage remains unavailable; producer completeness is
        unverified. No provider IDs, raw usage attributes or private ledger metadata are returned.
      responses:
        "200":
          description: Recorded, tenant-scoped accounting. For current CI wallet and runtime controls, use /api/management/v1/ci endpoints.
          headers:
            Cache-Control:
              schema:
                type: string
                const: private, no-store
              description: Private financial responses must not be cached.
            Vary:
              schema:
                type: string
                const: Authorization, Origin
              description: Credential and origin response partitioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordedBilling"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "503":
          description: The recorded-finance source is unavailable, inconsistent or past its bounded read deadline.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementError"
  /api/management/v1/billing/activity:
    get:
      operationId: listRecordedBillingActivity
      tags:
        - Recorded finance
      summary: List curated accounting activity
      description: Requires explicit billing:read and the key creator’s current owner, admin or billing
        role. Team and account come only from the stored key binding. The exact key generation/scope
        and membership are checked again in one read-only repeatable snapshot. No caller-supplied team
        override is supported. Read work has an 8-second transport deadline after the independent
        key/rate guards. Missing or current-day usage remains unavailable; producer completeness is
        unverified. No provider IDs, raw usage attributes or private ledger metadata are returned.
      parameters:
        - in: query
          name: cursor
          required: false
          description: Unchanged nextCursor from the previous page for this team, account and role.
          schema:
            type: string
            minLength: 1
            maxLength: 2048
      responses:
        "200":
          description: Recorded, tenant-scoped accounting. For current CI wallet and runtime controls, use /api/management/v1/ci endpoints.
          headers:
            Cache-Control:
              schema:
                type: string
                const: private, no-store
              description: Private financial responses must not be cached.
            Vary:
              schema:
                type: string
                const: Authorization, Origin
              description: Credential and origin response partitioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordedActivity"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "503":
          description: The recorded-finance source is unavailable, inconsistent or past its bounded read deadline.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementError"
  /api/management/v1/limits:
    get:
      operationId: getRecordedLimits
      tags:
        - Recorded finance
      summary: Read recorded limits and runtime availability
      description: Requires explicit billing:read and the key creator’s current owner, admin or billing
        role. Team and account come only from the stored key binding. The exact key generation/scope
        and membership are checked again in one read-only repeatable snapshot. No caller-supplied team
        override is supported. Read work has an 8-second transport deadline after the independent
        key/rate guards. Missing or current-day usage remains unavailable; producer completeness is
        unverified. No provider IDs, raw usage attributes or private ledger metadata are returned.
      responses:
        "200":
          description: Recorded, tenant-scoped accounting. For current CI wallet and runtime controls, use /api/management/v1/ci endpoints.
          headers:
            Cache-Control:
              schema:
                type: string
                const: private, no-store
              description: Private financial responses must not be cached.
            Vary:
              schema:
                type: string
                const: Authorization, Origin
              description: Credential and origin response partitioning.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RecordedLimits"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
        "429":
          $ref: "#/components/responses/TooManyRequests"
        "503":
          description: The recorded-finance source is unavailable, inconsistent or past its bounded read deadline.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ManagementError"
components:
  securitySchemes:
    ManagementKey:
      type: http
      scheme: bearer
      bearerFormat: bbm_ management key
      description: |
        A team-bound management key with the endpoint's required scope.
        Dashboard cookies, sandbox keys, and OIDC tokens are not accepted.
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: |
        Optional team-scoped mutation key, bound to the caller and request.
        A conflicting or in-progress request returns 409. Completed create and
        rotate requests also return 409 on replay; their secrets are never stored
        for replay. Completed revocation requests can replay their result.
      schema:
        type: string
        minLength: 1
        maxLength: 128
        pattern: '^[!-~]{1,128}$'
    ApiKeyId:
      name: apiKeyId
      in: path
      required: true
      description: The key metadata ID returned by list or create; not the key secret.
      schema:
        type: string
  headers:
    NoStore:
      description: One-time secrets must not be cached.
      schema:
        type: string
        const: no-store
  responses:
    Conflict:
      description: Conflicting, in-progress, or sensitive one-time response replay.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
    BadRequest:
      description: Invalid body, fields, or values.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
    Unauthorized:
      description: Missing, malformed, invalid, or revoked management key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
    Forbidden:
      description: Current role, scope, or key ownership does not permit this operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
    NotFound:
      description: The requested team, membership, or manageable active key was not found.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
    TooManyRequests:
      description: The request rate limit has been reached.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementError'
  schemas:
    TeamIdentity:
      type: object
      additionalProperties: false
      required: [id, name, slug, role]
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        slug:
          type: string
        role:
          type: string
          enum: [owner, admin, member, billing]
    ManagementScope:
      type: string
      description: Explicit team permissions, constrained by the creator’s current membership and role.
      enum:
        - teams:read
        - teams:write
        - members:read
        - members:write
        - keys:read
        - keys:write
        - billing:read
        - billing:write
        - audit:read
        - ci:read
        - ci:write
    ManagementKeyMetadata:
      type: object
      additionalProperties: false
      required: [id, name, keyPrefix, keyLastFour, scopes, expiresAt, createdAt, lastUsedAt]
      properties:
        id:
          type: string
        name:
          type: string
        keyPrefix:
          type: string
        keyLastFour:
          type: string
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/ManagementScope'
        createdAt:
          type: string
          format: date-time
        expiresAt:
          type: [string, 'null']
          format: date-time
        lastUsedAt:
          type: [string, 'null']
          format: date-time
    ManagementKeySecret:
      type: string
      readOnly: true
      pattern: '^bbm_[a-f0-9]{64}$'
      description: One-time secret returned only by create or rotate. Do not log or persist in browser storage.
    ManagementError:
      type: object
      required: [ok, type, status, code, message, error, requestId]
      properties:
        ok:
          type: boolean
          const: false
        type:
          type: string
          const: management.error
        status:
          type: integer
        code:
          type: string
        message:
          type: string
        requestId:
          type: [string, 'null']
        error:
          type: object
          required: [code, message, status]
          properties:
            code:
              type: string
            message:
              type: string
            status:
              type: integer
            details: {}
    SignedMicros:
      type: string
      pattern: ^(0|-?[1-9][0-9]{0,18})$
      description: Exact signed integer micro-USD, within PostgreSQL bigint bounds. One USD is 1000000
        micro-USD. Never convert through a floating-point number.
    NonnegativeMicros:
      type: string
      pattern: ^(0|[1-9][0-9]{0,18})$
      description: Exact nonnegative PostgreSQL bigint micro-USD as a decimal string.
    AggregateMicros:
      type: string
      pattern: ^(0|[1-9][0-9]{0,23})$
      description: Exact aggregate micro-USD, which can exceed one PostgreSQL row value.
    UsageQuantity:
      type: string
      pattern: ^(0|[1-9][0-9]{0,35})\.[0-9]{6}$
      description: Nonnegative resource quantity with exactly six decimal places.
    UsageDimension:
      type: string
      enum:
        - sandbox_vcpu_seconds
        - sandbox_ram_gib_seconds
        - sandbox_snapshot_gib_hours
        - ci_minutes
    RecordedTotals:
      type: object
      additionalProperties: false
      required:
        - amountMicros
        - byProduct
        - quantities
      properties:
        amountMicros:
          $ref: "#/components/schemas/AggregateMicros"
        byProduct:
          type: object
          additionalProperties: false
          required:
            - sandbox
            - ci
          properties:
            sandbox:
              oneOf:
                - $ref: "#/components/schemas/AggregateMicros"
                - type: "null"
            ci:
              oneOf:
                - $ref: "#/components/schemas/AggregateMicros"
                - type: "null"
        quantities:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
              - dimension
              - quantity
            properties:
              dimension:
                $ref: "#/components/schemas/UsageDimension"
              quantity:
                $ref: "#/components/schemas/UsageQuantity"
          minItems: 0
          maxItems: 4
    RecordedDay:
      oneOf:
        - type: object
          additionalProperties: false
          required:
            - day
            - state
            - snapshotAt
            - refreshPending
            - totals
          properties:
            day:
              type: string
              format: date
              pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
            state:
              type: string
              const: available
            snapshotAt:
              type: string
              format: date-time
            refreshPending:
              type: boolean
            totals:
              $ref: "#/components/schemas/RecordedTotals"
        - type: object
          additionalProperties: false
          required:
            - day
            - state
            - snapshotAt
            - refreshPending
            - totals
          properties:
            day:
              type: string
              format: date
              pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
            state:
              type: string
              enum:
                - missing
                - in_progress
            snapshotAt:
              type: "null"
            refreshPending:
              type: boolean
            totals:
              type: "null"
    RecordedAccounting:
      oneOf:
        - type: object
          additionalProperties: false
          required:
            - state
            - ledgerNetMicros
            - usedThisPeriodMicros
            - budgetMicros
            - budgetReached
            - periodStart
            - periodEnd
            - updatedAt
          properties:
            state:
              type: string
              const: available
            ledgerNetMicros:
              $ref: "#/components/schemas/SignedMicros"
            usedThisPeriodMicros:
              $ref: "#/components/schemas/NonnegativeMicros"
            budgetMicros:
              oneOf:
                - $ref: "#/components/schemas/NonnegativeMicros"
                - type: "null"
            budgetReached:
              type:
                - boolean
                - "null"
            periodStart:
              type: string
              format: date-time
            periodEnd:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
        - type: object
          additionalProperties: false
          required:
            - state
          properties:
            state:
              type: string
              const: unavailable
    StoredBillingStatus:
      type: string
      enum:
        - active
        - inactive
        - trialing
        - incomplete
        - incomplete_expired
        - past_due
        - canceled
        - unpaid
        - paused
        - unknown
    RecordedUsage:
      type: object
      additionalProperties: false
      required:
        - teamId
        - viewerAccountId
        - role
        - currency
        - observedAt
        - source
        - producerCompleteness
        - range
        - coverage
        - days
        - summary
        - breakdown
      properties:
        teamId:
          type: string
          format: uuid
        viewerAccountId:
          type: string
          format: uuid
        role:
          type: string
          enum:
            - owner
            - admin
            - billing
        currency:
          type: string
          const: USD
        observedAt:
          type: string
          format: date-time
        source:
          type: string
          const: postgres_daily_snapshots
        producerCompleteness:
          type: string
          const: unverified
        range:
          type: object
          additionalProperties: false
          required:
            - from
            - to
            - product
            - timezone
            - resolution
          properties:
            from:
              type: string
              format: date
              pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
            to:
              type: string
              format: date
              pattern: ^20[0-9]{2}-[0-9]{2}-[0-9]{2}$
            product:
              type: string
              enum:
                - all
                - sandbox
                - ci
            timezone:
              type: string
              const: UTC
            resolution:
              type: string
              const: day
        coverage:
          type: object
          additionalProperties: false
          required:
            - available
            - missing
            - inProgress
          properties:
            available:
              type: integer
              minimum: 0
              maximum: 366
            missing:
              type: integer
              minimum: 0
              maximum: 366
            inProgress:
              type: integer
              minimum: 0
              maximum: 1
        days:
          type: array
          items:
            $ref: "#/components/schemas/RecordedDay"
          minItems: 1
          maxItems: 366
        summary:
          oneOf:
            - $ref: "#/components/schemas/RecordedTotals"
            - type: "null"
        breakdown:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
              - product
              - dimension
              - sku
              - quantity
              - amountMicros
            properties:
              product:
                type: string
                enum:
                  - sandbox
                  - ci
              dimension:
                $ref: "#/components/schemas/UsageDimension"
              sku:
                type: string
                pattern: ^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,127}$
              quantity:
                $ref: "#/components/schemas/UsageQuantity"
              amountMicros:
                $ref: "#/components/schemas/AggregateMicros"
          minItems: 0
          maxItems: 500
    RecordedBilling:
      type: object
      additionalProperties: false
      required:
        - teamId
        - viewerAccountId
        - role
        - currency
        - observedAt
        - accounting
        - storedBillingStatus
        - subscription
        - providerSynchronization
        - providerActions
      properties:
        teamId:
          type: string
          format: uuid
        viewerAccountId:
          type: string
          format: uuid
        role:
          type: string
          enum:
            - owner
            - admin
            - billing
        currency:
          type: string
          const: USD
        observedAt:
          type: string
          format: date-time
        accounting:
          $ref: "#/components/schemas/RecordedAccounting"
        storedBillingStatus:
          $ref: "#/components/schemas/StoredBillingStatus"
        subscription:
          oneOf:
            - type: object
              additionalProperties: false
              required:
                - status
                - cancelAtPeriodEnd
                - currentPeriodEnd
                - updatedAt
              properties:
                status:
                  $ref: "#/components/schemas/StoredBillingStatus"
                cancelAtPeriodEnd:
                  type: boolean
                currentPeriodEnd:
                  oneOf:
                    - type: string
                      format: date-time
                    - type: "null"
                updatedAt:
                  type: string
                  format: date-time
            - type: "null"
        providerSynchronization:
          type: string
          const: unavailable
        providerActions:
          type: string
          const: unavailable
    RecordedActivity:
      type: object
      additionalProperties: false
      required:
        - teamId
        - viewerAccountId
        - role
        - currency
        - observedAt
        - entries
        - nextCursor
      properties:
        teamId:
          type: string
          format: uuid
        viewerAccountId:
          type: string
          format: uuid
        role:
          type: string
          enum:
            - owner
            - admin
            - billing
        currency:
          type: string
          const: USD
        observedAt:
          type: string
          format: date-time
        entries:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
              - id
              - type
              - deltaMicros
              - occurredAt
              - createdAt
            properties:
              id:
                type: string
                format: uuid
              type:
                type: string
                enum:
                  - grant
                  - usage
                  - adjustment
                  - refund
              deltaMicros:
                $ref: "#/components/schemas/SignedMicros"
                description: A nonzero exact signed integer micro-USD delta.
              occurredAt:
                type: string
                format: date-time
              createdAt:
                type: string
                format: date-time
          minItems: 0
          maxItems: 50
        nextCursor:
          oneOf:
            - type: string
              minLength: 1
              maxLength: 2048
              description: Opaque signed cursor bound to team, creator account and current role. Keep it unchanged.
            - type: "null"
    RecordedLimits:
      type: object
      additionalProperties: false
      required:
        - teamId
        - viewerAccountId
        - role
        - currency
        - observedAt
        - operational
        - financial
        - budgetEnforcement
        - alerts
        - increaseRequests
      properties:
        teamId:
          type: string
          format: uuid
        viewerAccountId:
          type: string
          format: uuid
        role:
          type: string
          enum:
            - owner
            - admin
            - billing
        currency:
          type: string
          const: USD
        observedAt:
          type: string
          format: date-time
        operational:
          type: object
          additionalProperties: false
          required:
            - teamId
            - sandbox
            - ci
            - budget
            - payment
            - abuse
          properties:
            teamId:
              type: string
              format: uuid
            sandbox:
              type: object
              additionalProperties: false
              required:
                - availability
                - concurrency
              properties:
                availability:
                  type: string
                  const: unavailable
                concurrency:
                  type: "null"
            ci:
              type: object
              additionalProperties: false
              required:
                - availability
                - concurrency
              properties:
                availability:
                  type: string
                  const: unavailable
                concurrency:
                  type: "null"
            budget:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - reached
                  properties:
                    reached:
                      type: boolean
                - type: "null"
            payment:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - failed
                  properties:
                    failed:
                      type: boolean
                - type: "null"
            abuse:
              oneOf:
                - type: object
                  additionalProperties: false
                  required:
                    - held
                  properties:
                    held:
                      type: boolean
                - type: "null"
        financial:
          $ref: "#/components/schemas/RecordedAccounting"
        budgetEnforcement:
          type: string
          const: admission_with_runtime_holds
        alerts:
          type: string
          const: recorded_usage
        increaseRequests:
          type: string
          const: unavailable
