Skip to content

Features API

Base: /org/features

Address features by key.

Create feature

POST /org/features
{
  "key": "sso",
  "name": "SSO",
  "kind": "flag",
  "description": "Single sign-on"
}

Limit example:

{
  "key": "seats",
  "name": "Seats",
  "kind": "limit"
}

Config examples:

{
  "key": "support_tier",
  "name": "Support tier",
  "kind": "config",
  "value_type": "enum",
  "options": ["basic", "priority", "dedicated"]
}
{
  "key": "export_timeout",
  "name": "Export timeout (s)",
  "kind": "config",
  "value_type": "number"
}
Field Required Rules
key yes max 64; lowercase letters, numbers, underscores, dashes; unique per org; immutable
kind yes flag | limit | config, immutable
value_type config only string | number | boolean | enum | json, immutable. Not allowed for flag or limit. See config value types
options enum only 1–100 unique strings, each 1–255 chars, in display order. Not allowed for other types
name yes 1–255 chars
description no max 2000

A feature object has value_type only when it's a config feature, and options only when it's an enum.

201 — feature object

409 — key already exists

422 — invalid body, or an unknown field ("period": "month" → Unknown field period.)

List features

GET /org/features

No query parameters. An unknown one is 422, one detail (?limit=10 → Unknown query parameter limit.).

200

{
  "features": [
    {
      "key": "sso",
      "name": "SSO",
      "description": "Single sign-on",
      "kind": "flag",
      "created_at": "2026-01-15T12:00:00.000Z",
      "updated_at": "2026-01-15T12:00:00.000Z"
    },
    {
      "key": "seats",
      "name": "Seats",
      "description": "",
      "kind": "limit",
      "created_at": "2026-01-15T12:00:00.000Z",
      "updated_at": "2026-01-15T12:00:00.000Z"
    },
    {
      "key": "support_tier",
      "name": "Support tier",
      "description": "",
      "kind": "config",
      "value_type": "enum",
      "options": ["basic", "priority", "dedicated"],
      "created_at": "2026-01-15T12:00:00.000Z",
      "updated_at": "2026-01-15T12:00:00.000Z"
    }
  ]
}

Get feature

GET /org/features/{key}

200 — feature · 404 — not found

Update feature

PATCH /org/features/{key}
{
  "name": "SSO (SAML/OIDC)",
  "description": "Updated copy"
}

key, kind, and value_type cannot change. Unknown fields are 422.

An enum's options can change: send the whole list. Adding and reordering always work.

{
  "options": ["basic", "priority", "dedicated", "enterprise"]
}

200 — feature

409 OPTION_IN_USE — a removed option is still the value of a plan grant or a live (unexpired) override. Nothing changes. details.usage names where:

{
  "error": {
    "type": "invalid_request_error",
    "code": "OPTION_IN_USE",
    "message": "\"priority\" is still used by 1 plan and 1 override. Change those first.",
    "request_id": "…",
    "details": {
      "resource": "feature",
      "id": "support_tier",
      "field": "options",
      "usage": [
        { "option": "priority", "plans": ["pro"], "overrides": ["cust_acme"] }
      ]
    }
  }
}

overrides lists subscriber ids.

422 — options on a feature that isn't an enum

Delete feature

DELETE /org/features/{key}

204 — deleted

409 — feature is still referenced by a plan or an override