BetterMenu Entitlements API

Account entitlement and plan status.

Operations 5

GET /entitlements/status Get Entitlement Status #
GET /entitlements/usage Get Usage Ledger #
GET /entitlements/plans List Purchasable Plans #
POST /entitlements/checkout Create Checkout Session #
POST /entitlements/portal Create Customer Portal Session #

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/bettermenu:bettermenu-entitlements-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

bettermenu-entitlements-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Studio Entitlements API
  description: '## Recipe versioning


    Recipe is the aggregate; versions are read-only history. Use the table

    below to pick the right call.


    | I want to… | Use… |

    |-------------------------------------------------------------|------------------------------------------------------------|

    | Edit a recipe safely without overwriting someone else''s | `GET /recipes/{id}` → `If-Match` → `PATCH`/`POST`/`DELETE` |

    | See a recipe at a point in the past | `GET /recipes/{id}/versions/{version_id}` |

    | Replay the chain of state changes (signed, tamper-evident) | `GET /recipes/{id}/versions` |

    | See who changed what and when, with event detail | `GET /recipes/{id}/audit-trail` |

    | Understand why a write returned `412` | someone else edited; refetch and retry |


    The `version_id` returned on every recipe response is your edit token.

    Send it as `If-Match` on the next write; on conflict the server returns

    `412` with `current_version_id` so you can refetch and retry. There is

    no `POST /recipes/{id}/versions` — the system commits versions

    automatically when you mutate the recipe.


    The versions list and the audit trail answer different questions: the

    versions list is a tamper-evident chain of state snapshots you can

    replay; the audit trail is a filterable, event-typed log of what users

    and systems did to the recipe.'
  version: 2026-05-04.preview
  x-service-version: 0.47.0+ac83f7e
tags:
- name: Entitlements
  description: Account entitlement and plan status.
paths:
  /entitlements/status:
    get:
      tags:
      - Entitlements
      summary: Get Entitlement Status
      description: Read the calling organization's subscription plan, trial state, pending cancellation, feature gates, and per-quota usage. quotas[key].limit reflects the effective limit (the plan's trial limit when is_trialing is true). metered_usage_enabled reports whether the organization accepts charges beyond its included monthly allowance.
      operationId: getEntitlementStatus
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EntitlementStatusResponse'
      x-bettermenu-mcp-status: ga
      x-required-permission: studio.billing.read
  /entitlements/usage:
    get:
      tags:
      - Entitlements
      summary: Get Usage Ledger
      description: 'Read the calling organization''s recorded AI usage for the current billing cycle: the credit total and which capabilities spent it, largest first, against the allowance the plan includes. credits_overage is what the cycle is past that allowance; charges_apply says whether an overage is actually charged, and is false while the AI quota is in its preview period or while the organization does not permit usage beyond its allowance.'
      operationId: getUsageLedger
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UsageResponse'
      x-bettermenu-mcp-status: preview
      x-required-permission: studio.billing.read
  /entitlements/plans:
    get:
      tags:
      - Entitlements
      summary: List Purchasable Plans
      description: List the subscription plans the calling organization can purchase, including display name, feature gates, recurring price, and which plan is currently active.
      operationId: listEntitlementPlans
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlansResponse'
      x-bettermenu-mcp-status: restricted
      x-required-permission: studio.billing.read
  /entitlements/checkout:
    post:
      tags:
      - Entitlements
      summary: Create Checkout Session
      description: Create a Stripe Checkout session for the calling organization to subscribe to a paid plan. Returns a hosted URL to redirect the customer to. Reuses the organization's existing billing customer.
      operationId: createCheckoutSession
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CheckoutRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CheckoutResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      x-bettermenu-mcp-status: restricted
      x-required-permission: studio.billing.manage
  /entitlements/portal:
    post:
      tags:
      - Entitlements
      summary: Create Customer Portal Session
      description: Create a Stripe Customer Portal session so the calling organization can manage its payment method, view invoices, or cancel its subscription. Returns a hosted URL to redirect the customer to.
      operationId: createPortalSession
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PortalRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PortalResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      x-bettermenu-mcp-status: restricted
      x-required-permission: studio.billing.manage
components:
  schemas:
    PurchasablePlan:
      properties:
        plan_name:
          type: string
          title: Plan Name
          description: Internal identifier of the plan.
        display_name:
          type: string
          title: Display Name
          description: Human-readable plan name for the UI.
        feature_gates:
          items:
            type: string
          type: array
          title: Feature Gates
          description: Feature gate identifiers this plan unlocks.
        price:
          $ref: '#/components/schemas/BillingPrice'
          description: Recurring price for this plan.
        is_current:
          type: boolean
          title: Is Current
          description: True when this is the calling organization's active plan.
      type: object
      required:
      - plan_name
      - display_name
      - feature_gates
      - price
      - is_current
      title: PurchasablePlan
      description: 'A plan an organization can buy, with display + price metadata.


        Returned by ``GET /entitlements/plans``. Internal non-subscription tiers

        (past_due/expired/cancelled) and the default trial are never purchasable and

        are excluded from this list.'
    AllowanceView:
      properties:
        kind:
          type: string
          title: Kind
          description: One of "capped" (a ceiling, in credits), "uncapped" (the plan meters this without limiting it), or "not_entitled" (billing has lapsed, so there is no allowance at all).
        credits:
          anyOf:
          - type: integer
          - type: 'null'
          title: Credits
          description: The ceiling, present only when kind is "capped". Absent for the other two, because neither has one — and 0 would be a ceiling of zero, which makes every credit an overage.
      type: object
      required:
      - kind
      title: AllowanceView
      description: 'What a plan allows for a cycle, tagged so the three cases stay distinct.


        Mirrors ``entitlements.allowance.QuotaGrant`` deliberately: the wire shape

        and the internal type have the same three cases, so they cannot drift into

        the collapse this replaces.


        ``kind`` is a plain string rather than an enum in the schema, so a fourth

        case later does not break a strict client parsing today''s closed set. The

        server''s own type is exhaustive; the wire stays open.'
    EntitlementStatusResponse:
      properties:
        plan_name:
          type: string
          title: Plan Name
        display_name:
          type: string
          title: Display Name
        is_trialing:
          type: boolean
          title: Is Trialing
        trial_ends_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Trial Ends At
        trial_days_remaining:
          anyOf:
          - type: integer
          - type: 'null'
          title: Trial Days Remaining
        pending_cancellation_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Pending Cancellation At
        feature_gates:
          items:
            type: string
          type: array
          title: Feature Gates
        quotas:
          additionalProperties:
            $ref: '#/components/schemas/QuotaStatusEntry'
          type: object
          title: Quotas
        write_access:
          type: string
          title: Write Access
        write_access_reason:
          anyOf:
          - type: string
          - type: 'null'
          title: Write Access Reason
        metered_usage_enabled:
          type: boolean
          title: Metered Usage Enabled
        is_free_plan:
          type: boolean
          title: Is Free Plan
          description: 'True when the organization''s current plan is the no-card Free plan: no subscription, and quotas that stop at their limit rather than billing an overage. Clients use this instead of matching plan_name.'
      type: object
      required:
      - plan_name
      - display_name
      - is_trialing
      - trial_ends_at
      - trial_days_remaining
      - pending_cancellation_at
      - feature_gates
      - quotas
      - write_access
      - write_access_reason
      - metered_usage_enabled
      - is_free_plan
      title: EntitlementStatusResponse
    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
    PortalResponse:
      properties:
        url:
          type: string
          title: Url
          description: Hosted Stripe Customer Portal URL to redirect the customer to.
      type: object
      required:
      - url
      title: PortalResponse
    CheckoutRequest:
      properties:
        plan_name:
          type: string
          title: Plan Name
          description: Internal identifier of the plan to subscribe to (e.g. 'pro').
        success_url:
          type: string
          title: Success Url
          description: Absolute URL Stripe redirects to after a completed checkout.
        cancel_url:
          type: string
          title: Cancel Url
          description: Absolute URL Stripe redirects to if the customer cancels.
      type: object
      required:
      - plan_name
      - success_url
      - cancel_url
      title: CheckoutRequest
    PortalRequest:
      properties:
        return_url:
          type: string
          title: Return Url
          description: Absolute URL Stripe returns the customer to after the portal.
      type: object
      required:
      - return_url
      title: PortalRequest
    PlansResponse:
      properties:
        plans:
          items:
            $ref: '#/components/schemas/PurchasablePlan'
          type: array
          title: Plans
          description: Purchasable plans with display, price, and current-plan flag.
      type: object
      required:
      - plans
      title: PlansResponse
    CheckoutResponse:
      properties:
        url:
          type: string
          title: Url
          description: Hosted Stripe Checkout URL to redirect the customer to.
      type: object
      required:
      - url
      title: CheckoutResponse
    CapabilityUsage:
      properties:
        capability:
          type: string
          title: Capability
          description: Stable key, e.g. "paste_and_go".
        credits:
          type: integer
          title: Credits
        requests:
          anyOf:
          - type: integer
          - type: 'null'
          title: Requests
          description: 'Requests that earned credits under this capability. Null when the count is not recorded for this cycle, which is every cycle already in flight when the counter was introduced. Null rather than zero on purpose: zero says a capability earned credits across no requests, which is not a state any request can produce, so a reader shown 0 would be shown a contradiction rather than a gap.'
      type: object
      required:
      - capability
      - credits
      title: CapabilityUsage
      description: One capability's share of the cycle.
    QuotaStatusEntry:
      properties:
        limit:
          type: integer
          title: Limit
        used:
          type: integer
          title: Used
        remaining:
          type: integer
          title: Remaining
        resets_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Resets At
        overage_per_unit_cents:
          anyOf:
          - type: string
          - type: 'null'
          title: Overage Per Unit Cents
      type: object
      required:
      - limit
      - used
      - remaining
      - resets_at
      title: QuotaStatusEntry
    BillingPrice:
      properties:
        price_id:
          type: string
          title: Price Id
          description: Stripe Price ID used as the Checkout line item.
        amount_cents:
          type: integer
          title: Amount Cents
          description: Recurring amount in the smallest currency unit (e.g. cents).
        currency:
          type: string
          title: Currency
          description: ISO 4217 currency code.
          default: usd
        interval:
          type: string
          title: Interval
          description: Billing interval for the recurring price (e.g. month, year).
          default: month
      type: object
      required:
      - price_id
      - amount_cents
      title: BillingPrice
      description: 'Display + checkout metadata for a purchasable plan''s recurring price.


        Single source of truth for both ``GET /entitlements/plans`` (display) and

        ``POST /entitlements/checkout`` (``price_id`` fed to Stripe). Loaded from

        the ``ENTITLEMENTS_STRIPE_PRICE_MAP`` config so the read path never has to

        call Stripe to render a pricing table.'
    UsageResponse:
      properties:
        period_key:
          type: string
          title: Period Key
        credits_used:
          type: integer
          title: Credits Used
        allowance:
          $ref: '#/components/schemas/AllowanceView'
          description: What the plan allows this cycle, as a tagged object rather than a nullable number. A null limit had to mean both 'no ceiling' and 'no entitlement', which is exactly how a cancelled organization came to be reported as unlimited. Read the kind, then the fields that kind carries.
        credits_overage:
          type: integer
          title: Credits Overage
          description: 'Credits beyond the included allowance: credits_used minus credits_included, floored at zero, and zero when the allowance is unlimited. Named for the rate card''s own term, which is also what reaches the meter event and the invoice line, so a disputed bill and this payload use one word for one thing.'
        charges_apply:
          type: boolean
          title: Charges Apply
          description: 'Whether an overage in this cycle is actually charged. False while the AI quota is in its preview period, when usage is recorded and billed to nobody, and for an organization with no paid subscription, whose allowance is a hard stop. Separate from credits_overage because the two are different facts: one is the regime, the other is this cycle.'
        unattributed_credits:
          type: integer
          title: Unattributed Credits
          description: 'Credits in credits_used that by_capability does not account for, floored at zero. Normally zero. It is positive for a cycle that was already in flight when per-capability counting began: the cycle total covers the whole period while the breakdown covers only the part after it, so the parts do not sum to the whole. Reported rather than hidden, because a breakdown that silently fails to add up is the one thing a screen built to be checkable must not do. Self-clearing: no cycle started after counting began can have it.'
        resets_at:
          anyOf:
          - type: string
            format: date-time
          - type: 'null'
          title: Resets At
          description: 'When this period ends and the allowance renews: the 1st of next month (UTC) for an allowance counted per calendar month, otherwise the next billing-cycle boundary. Not derivable from period_key, which is the cycle''s clamped start day and says nothing about the next boundary in a month too short to hold the anchor. Null when a billing-cycle allowance has no plan row to take an anchor from. The same instant getEntitlementStatus reports, from one helper.'
        by_capability:
          items:
            $ref: '#/components/schemas/CapabilityUsage'
          type: array
          title: By Capability
          description: Largest consumer first. Empty when the cycle recorded none.
      type: object
      required:
      - period_key
      - credits_used
      - allowance
      - credits_overage
      - charges_apply
      - unattributed_credits
      - resets_at
      - by_capability
      title: UsageResponse
      description: One organization's usage for one billing cycle, and what it comes to.
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError