---
title: "Update a subscription plan"
method: PUT
path: "/subscription/plans/{plan_id}"
tags: ["Subscription Plans"]
---

# Update a subscription plan

`PUT /subscription/plans/{plan_id}`

## Request

- Base URL: `https://app.mammoth.io/api/v2`
- URL: `https://app.mammoth.io/api/v2/subscription/plans/{plan_id}`
- Auth: one of:
  - HTTP bearer
  - API key in header `X-API-KEY` and API key in header `X-API-SECRET` and API key in header `X-WORKSPACE-ID`

## Path parameters

- `plan_id` integer, required

## Request body

- UpdatePlanRequestSchema
  - `name` string, nullable: Plan name
  - `display_name` string, nullable: Plan display name
  - `description` string, nullable: Plan description
  - `monthly_price` number, nullable: Monthly price in USD
  - `annual_price` number, nullable: Annual price in USD
  - `annual_only` boolean, nullable: Whether plan is annual only
  - `is_self_serve` boolean, nullable: Whether users can self-subscribe
  - `trial_days` integer, nullable: Trial period in days
  - `storage_amount` integer, nullable: Included storage in GB
  - `max_storage` integer, nullable: Maximum storage in GB
  - `max_users` integer, nullable: Maximum number of users
  - `no_of_users` integer, nullable: Number of included users
  - `seat_price` number, nullable: Price per additional user seat
  - `number_of_tiers` integer, nullable: Number of storage tiers
  - `storage_block_size` integer, nullable: Storage block size in GB
  - `tiers` SubscriptionSchemasStorageTierSchema[], nullable: Storage pricing tiers
    - `gb` integer, required: Storage amount in GB
    - `price_per_gb` number, required: Price per GB in USD
  - `uses_inline_pricing` boolean, nullable: Bill this plan with composed price_data (plan price plus the chosen storage option) instead of stored Stripe prices
  - `storage_options` StorageOptionRequestSchema[], nullable: Replaces the plan's active storage sizes; sizes left out are archived. Omit to leave the catalog alone.
    - `storage_gb` integer, required: Total storage the option grants, in GB
    - `monthly_price` number, required: Monthly add in USD on top of the plan price
    - `annual_price` number, required: Annual add in USD on top of the plan price
  - `connector_profile_id` integer, nullable: Connector profile ID
  - `feature_profile_id` integer, nullable: Feature profile ID
  - `is_purchasable` boolean, nullable: Whether a new customer may pick this plan
  - `lifecycle` 'current' | 'legacy' | 'system' | 'null', nullable: Catalog population: current, legacy or system

## Response `200`

Request fulfilled, document follows

- PlanResponseSchema
  - `plan` PlanSchema, required
    - `id` integer, required
    - `name` string, required
    - `display_name` string, nullable
    - `description` string, nullable
    - `currency` string, required
    - `monthly_price` number, nullable
    - `annual_only` boolean: Indicates if the plan is annual-only.
    - `annual_price` number, nullable
    - `storage_amount` integer, required
    - `storage_block_size` integer, nullable: Block size for storage increments.
    - `trial_days` integer, nullable
    - `is_self_serve` boolean, required
    - `is_purchasable` boolean: False = displayed in the catalog so it matches the pricing page, but never sold from it (it resolves to a Deal).
    - `lifecycle` string: current | legacy | system. Only CURRENT rows are editable: the legacy estate is read-only until its migration terms are decided.
    - `max_storage` integer, nullable
    - `max_users` integer, nullable
    - `no_of_users` integer, nullable
    - `seat_price` integer, nullable
    - `number_of_tiers` integer, required
    - `tiers` SchemaStorageTierSchema[], nullable
      - `gb` integer, required
      - `price_per_gb` number, required
    - `uses_inline_pricing` boolean
    - `storage_options` PlanStorageOptionSchema[], nullable: Selectable storage sizes, base first, for inline-pricing plans; null on legacy plans, which price storage through addons.
      - `id` integer, nullable: The stored option this entry came from; null on the plan's included storage, which is composed rather than stored.
      - `storage_gb` integer, required
      - `monthly_price` number, required
      - `annual_price` number, required
      - `is_base` boolean, required
      - `status` string, nullable: Status of the stored option; null on the base.
    - `connector_profile_id` integer, nullable
    - `feature_profile_id` integer, nullable
    - `stripe_product_id` string, nullable
    - `stripe_monthly_price_id` string, nullable
    - `stripe_annual_price_id` string, nullable
    - `status` string, required
    - `created_at` string, nullable
    - `updated_at` string, nullable
    - `subscription_count` integer, nullable
    - `connector_profile` ConnectorProfileSchema
      - `id` integer, required
      - `name` string, required
      - `description` string, nullable
      - `created_at` string, nullable
      - `updated_at` string, nullable
      - `connectors` ConnectorSchema[], nullable
        - `id` integer, required
        - `name` string, required
        - `description` string, nullable
        - `price_per_month` number, nullable
        - `enabled` boolean, required
        - `bucket` string, nullable: file | database | app | custom — the access model (admin-v2.1 D6): a plan's connectorAccess level reaches connectors by bucket
        - `created_at` string, nullable
        - `updated_at` string, nullable
        - `used_in_profiles` string[], nullable
        - `profile_count` integer, nullable
      - `connectors_count` integer, nullable
      - `used_in_plans` string[], nullable
      - `plan_count` integer, nullable
    - `feature_profile` FeatureProfileSchema
      - `id` integer, required
      - `name` string, required
      - `description` string, nullable
      - `created_at` string, nullable
      - `updated_at` string, nullable
      - `features` SubscriptionsSchemaFeatureSchema[], nullable
        - `id` integer, required
        - `name` string, required
        - `description` string, nullable
        - `enabled` boolean, required
        - `kind` string, nullable: capacity | meter | enum | switch
        - `unit` string, nullable: Display unit (GB, /mo, days)
        - `group_name` string, nullable: Scale | Access | Brand | Governance | Service. NULL means the key is NEVER GATED — granted on every plan, listed apart from the registry
        - `enforcement` string, nullable: enforced | unenforced | unbuilt | unconfirmed | split | commitment
        - `note` string, nullable: What the product actually does today
        - `created_at` string, nullable
        - `updated_at` string, nullable
        - `used_in_profiles` string[], nullable
        - `values` string[], nullable
        - `value` string, nullable
        - `profile_count` integer, nullable
        - `number_of_values` integer, nullable
      - `features_count` integer, nullable
      - `used_in_plans` string[], nullable
      - `plan_count` integer, nullable
    - `connector_access` string, nullable: The plan's connectorAccess level as the resolver reads it (no level reads all). Set on the self-serve catalog.
    - `access_connectors` string[], nullable: The connector names that level reaches. The connector profile decides no access (decision 2026-10-06).
  - `message` string, nullable

## Other responses

- `400`: Bad request syntax or unsupported method

---

[API](https://skmtc.dev/mammoth/apis/mammoth-analytics.md) · [All operations](https://skmtc.dev/mammoth/apis/mammoth-analytics/llms.txt) · [OpenAPI document](https://skmtc.dev/mammoth/apis/mammoth-analytics/revisions/5dfd1c296ded?raw)
