Kagura AI Internal Billing API

Internal service-authenticated plan and downgrade-eligibility endpoints

GitHub OpenAPI

Operations 5

PUT /internal/workspaces/{workspace_id}/plan Set Workspace Plan From Billing #
GET /internal/workspaces/{workspace_id}/plan Get Workspace Entitlement #
GET /internal/workspaces/{workspace_id}/owner Get Workspace Owner Check #
GET /internal/workspaces/{workspace_id}/downgrade-eligibility Get Downgrade Eligibility #
POST /internal/workspaces/{workspace_id}/capacity-lock-notice Send Capacity Lock Notice #

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/kagura-ai-com:kagura-ai-com-internal-billing-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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

kagura-ai-com-internal-billing-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Kagura Memory Cloud Internal Billing API
  description: Universal AI Memory Platform - Remote MCP Server + Web Management
  version: 0.158.1
tags:
- name: internal-billing
  description: Internal service-authenticated plan and downgrade-eligibility endpoints
paths:
  /internal/workspaces/{workspace_id}/plan:
    put:
      tags:
      - internal-billing
      summary: Set Workspace Plan From Billing
      description: 'Set a workspace''s entitlement (plan tier + addon quota) from billing.


        Idempotent, service-authenticated, internal-only. Sets ``plan_name``; when

        ``addons`` is provided it is applied as a FULL REPLACE (dimensions omitted

        from the map reset to 0) so a tier change cannot strand a prior tier''s addon

        bonus; omit ``addons`` to leave them unchanged. Does not perform destructive

        downgrade cascades (see module docstring). Returns the full applied addon state.'
      operationId: set_workspace_plan_from_billing_internal_workspaces__workspace_id__plan_put
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          title: Workspace Id
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/BillingPlanPush'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BillingPlanPushResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    get:
      tags:
      - internal-billing
      summary: Get Workspace Entitlement
      description: 'Read a workspace''s current entitlement + ``entitlement_source`` (#1095).


        Service-authenticated, internal-only. The external reconciler reads this to

        decide whether to reconcile a workspace (``external_billing``) or leave it

        untouched (``admin_grant``) — so a periodic billing reconcile never reverts a

        locally-owned admin/comp grant.

        ``created_at`` is the workspace''s creation time with an explicit UTC offset

        for billing-side time-based eligibility checks (#2706).'
      operationId: get_workspace_entitlement_internal_workspaces__workspace_id__plan_get
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          title: Workspace Id
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceEntitlementView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /internal/workspaces/{workspace_id}/owner:
    get:
      tags:
      - internal-billing
      summary: Get Workspace Owner Check
      description: 'Re-check whether ``sub`` currently owns a workspace (#2181).


        Service-authenticated, internal-only, read-only. The billing service calls

        this before a billing action so a user who has lost ownership since their

        billing session started (transfer, demotion, erasure) cannot act on the

        workspace''s subscription.


        ``is_owner`` is strict equality against the canonical owner pointer

        ``Workspace.owner_user_id`` (moved only by the ownership service and

        erasure). Identity links are not consulted (they share private contexts,

        not workspace roles) and there is no membership-table fallback.


        404 is returned ONLY when no workspace row has this id. A soft-deleted

        workspace answers 200 ``is_owner: false`` — a deliberate deviation from the

        entitlement read, which 404s on it: the billing service treats a literal

        404 as "this route is not deployed" and then falls back to its own session,

        so an existing-but-deleted workspace must fail closed with ``false``

        instead. A workspace with no owner pointer also answers ``false``. A row

        that is gone entirely (hard-deleted) answers 404 by the agreed contract.


        Raises:

        ValidationError: ``workspace_id`` is not a UUID or ``sub`` is blank (422).

        NotFoundException: no workspace row has this id (404).'
      operationId: get_workspace_owner_check_internal_workspaces__workspace_id__owner_get
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          title: Workspace Id
      - name: sub
        in: query
        required: true
        schema:
          type: string
          minLength: 1
          maxLength: 255
          description: User id (``users.user_id``) whose ownership is re-checked
          title: Sub
        description: User id (``users.user_id``) whose ownership is re-checked
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WorkspaceOwnerView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /internal/workspaces/{workspace_id}/downgrade-eligibility:
    get:
      tags:
      - internal-billing
      summary: Get Downgrade Eligibility
      description: 'Report whether a workspace''s usage fits each lower tier (#1123).


        Service-authenticated, internal-only. memory-cloud is the usage SoT; the

        external billing service gates its portal downgrade UI on this so it never

        offers a downgrade that current usage cannot satisfy (purchased addons are

        kept — the fit is against the target tier base + retained addon bonuses).

        The absolute ``PUT .../plan`` push stays reconcile-safe and does NOT itself

        enforce this guard; enforcement is the portal''s responsibility, informed by

        this read. Soft-deleted workspaces 404 (consistent with the entitlement read).'
      operationId: get_downgrade_eligibility_internal_workspaces__workspace_id__downgrade_eligibility_get
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          title: Workspace Id
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DowngradeEligibilityView'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /internal/workspaces/{workspace_id}/capacity-lock-notice:
    post:
      tags:
      - internal-billing
      summary: Send Capacity Lock Notice
      description: 'Warn the owner before a paid period ends that Free would lock the workspace (#1941).


        memory-cloud does not store ``current_period_end``, so the billing service

        decides WHEN (e.g. 7 days before the end of a cancelled subscription) and

        calls this. memory-cloud evaluates the projected Free state with the same

        counting as the capacity lock — Free tier limits plus the bonuses a

        downgrade keeps, files of deleted contexts excluded — and, when over,

        emails the workspace owner (plain text, no memory content).


        Idempotent per ``(workspace, period_end)``: a repeat answers

        ``sent=false, reason="already_sent"``. In addition, at most one notice per

        workspace per 24 hours (``reason="cooldown"``). A failed delivery releases

        both claims so a retry can send. 404 for a missing or soft-deleted workspace.'
      operationId: send_capacity_lock_notice_internal_workspaces__workspace_id__capacity_lock_notice_post
      parameters:
      - name: workspace_id
        in: path
        required: true
        schema:
          type: string
          title: Workspace Id
      - name: authorization
        in: header
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Authorization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CapacityLockNoticeRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CapacityLockNoticeResult'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    TierDowngradeEligibility:
      properties:
        target_plan:
          type: string
          title: Target Plan
        eligible:
          type: boolean
          title: Eligible
        blockers:
          items:
            $ref: '#/components/schemas/DowngradeBlocker'
          type: array
          title: Blockers
      type: object
      required:
      - target_plan
      - eligible
      - blockers
      title: TierDowngradeEligibility
      description: Whether the workspace's usage fits one specific lower tier.
    DowngradeCleanup:
      type: string
      enum:
      - remove_members
      - delete_contexts
      - delete_memories
      - revoke_resource_tokens
      - unshare_contexts
      - remove_connectors
      - disable_sleep_contexts
      - delete_files
      title: DowngradeCleanup
      description: The destructive cleanup a blocker requires (stable wire contract).
    WorkspaceOwnerView:
      properties:
        workspace_id:
          type: string
          title: Workspace Id
        sub:
          type: string
          title: Sub
        is_owner:
          type: boolean
          title: Is Owner
      type: object
      required:
      - workspace_id
      - sub
      - is_owner
      title: WorkspaceOwnerView
      description: 'Answer of the ownership re-check: is ``sub`` the workspace owner right now.'
    BillingPlanPush:
      properties:
        plan_name:
          type: string
          title: Plan Name
          description: 'Entitlement tier: one of the registered plan keys (free | basic | pro | promax)'
        status:
          anyOf:
          - type: string
            maxLength: 50
          - type: 'null'
          title: Status
          description: Billing subscription status (Stripe-agnostic free-form). Billing-owned; accepted for audit/forward-compat, NOT persisted or enforced here.
        current_period_end:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Current Period End
          description: Subscription period end. Billing-owned; accepted for audit, not persisted here.
        addons:
          anyOf:
          - additionalProperties:
              type: integer
            type: object
          - type: 'null'
          title: Addons
          description: 'Absolute addon bonus values keyed by addon dimension (memory, mcp_quota, rest_quota, public_quota, member, context, analysis, storage_mb, sleep_contexts, connector, memories_per_day, history_retention_days — days added to the 90-day operation history retention, at most 3650). FULL REPLACE: when provided this is the complete addon state — dimensions omitted from the map are reset to 0 (an empty object zeros all). Omit the field entirely (null) to leave existing addons unchanged (tier-only change).'
      type: object
      required:
      - plan_name
      title: BillingPlanPush
      description: Entitlement push from the billing service (#954 boundary contract).
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    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
    CapacityLockNoticeRequest:
      properties:
        period_end:
          type: string
          format: date-time
          title: Period End
          description: When the paid period ends and the workspace returns to Free
      type: object
      required:
      - period_end
      title: CapacityLockNoticeRequest
      description: Body of ``POST /internal/workspaces/{id}/capacity-lock-notice`` (#1941).
    CapacityLockNoticeResult:
      properties:
        sent:
          type: boolean
          title: Sent
        reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Reason
        over_memories:
          type: integer
          title: Over Memories
        over_bytes:
          type: integer
          title: Over Bytes
      type: object
      required:
      - sent
      - over_memories
      - over_bytes
      title: CapacityLockNoticeResult
      description: 'Outcome of a notice request. Never carries the recipient address.


        ``reason`` (when ``sent`` is false): ``not_billing_managed`` (the

        workspace''s entitlement is admin-managed or self-hosted — it is never

        locked, so it is never warned), ``within_capacity`` (the projected

        Free state fits — nothing to warn about), ``already_sent`` (a notice for

        this ``period_end`` was already sent), ``cooldown`` (a notice for this

        workspace was sent in the last 24 hours, for any ``period_end``),

        ``no_owner_email`` or ``delivery_failed`` (retry later; both claims are

        released).

        ``sent=true, reason="delivery_uncertain"``: the provider timed out after it

        may have accepted the email; the claim is kept, so it is never resent.'
    DowngradeEligibilityView:
      properties:
        workspace_id:
          type: string
          title: Workspace Id
        current_plan:
          type: string
          title: Current Plan
        targets:
          items:
            $ref: '#/components/schemas/TierDowngradeEligibility'
          type: array
          title: Targets
      type: object
      required:
      - workspace_id
      - current_plan
      - targets
      title: DowngradeEligibilityView
      description: Usage-fit downgrade eligibility for every tier below the current one (#1123).
    DowngradeBlocker:
      properties:
        dimension:
          $ref: '#/components/schemas/DowngradeDimension'
        usage:
          type: integer
          title: Usage
        limit:
          type: integer
          title: Limit
        overage:
          type: integer
          title: Overage
        cleanup:
          $ref: '#/components/schemas/DowngradeCleanup'
      type: object
      required:
      - dimension
      - usage
      - limit
      - overage
      - cleanup
      title: DowngradeBlocker
      description: 'One usage dimension that blocks (or requires cleanup before) a downgrade.


        ``overage`` is how much must be shed to fit the target. For ``shared_contexts``

        (a tier feature, not a numeric cap) the limit is 0 and ``overage`` equals the

        full shared-context count — all of them must be unshared. ``storage_bytes`` is

        in bytes and is the reducible figure of ``services/storage_counts.py`` (#1961):

        uploaded, not soft-deleted files that are workspace-scoped or in a live

        context — the same number the capacity lock uses, not the upload-quota

        counter.'
    BillingPlanPushResult:
      properties:
        workspace_id:
          title: Workspace Id
        plan_name:
          title: Plan Name
        addons:
          title: Addons
        entitlement_source:
          title: Entitlement Source
        status:
          title: Status
        current_period_end:
          title: Current Period End
        applied:
          title: Applied
      type: object
      required:
      - workspace_id
      - plan_name
      - addons
      - entitlement_source
      title: BillingPlanPushResult
      description: Echo of the applied entitlement (idempotent).
    DowngradeDimension:
      type: string
      enum:
      - members
      - contexts
      - memories
      - resource_tokens
      - shared_contexts
      - connectors
      - sleep_enabled_contexts
      - storage_bytes
      title: DowngradeDimension
      description: Usage dimensions that can block a downgrade (stable wire contract).
    WorkspaceEntitlementView:
      properties:
        workspace_id:
          type: string
          title: Workspace Id
        plan_name:
          type: string
          title: Plan Name
        addons:
          additionalProperties:
            type: integer
          type: object
          title: Addons
        entitlement_source:
          type: string
          title: Entitlement Source
        created_at:
          type: string
          format: date-time
          title: Created At
          description: Workspace creation time (ISO 8601 with explicit UTC)
      type: object
      required:
      - workspace_id
      - plan_name
      - addons
      - entitlement_source
      - created_at
      title: WorkspaceEntitlementView
      description: 'Current entitlement, provenance and workspace creation time (#1095, #2706).'