> ## Documentation Index
> Fetch the complete documentation index at: https://docs.telzino.com/llms.txt
> Use this file to discover all available pages before exploring further.

# List Feature Availability

> Returns every platform feature with whether it is available or locked for an account, reseller or organization

Use this endpoint to find out which capabilities an account, reseller or organization may
actually use, so your integration can hide a feature instead of letting a user reach a
write that fails with `403 forbidden`.

Availability is governed by [Feature Administration](/admin-guide/dashboard/feature-administration),
where a Partner or Reseller locks a feature for the levels beneath it. A lock is inherited:
one placed on an account applies to every reseller and organization under it, and one
placed on a reseller applies to all of its organizations.

## Choosing a scope

Pass at most one scope parameter. Supplying both, or supplying one with an empty value,
is rejected with `400`.

| Parameter | Reports availability for | Locks reflected |
| - | - | - |
| *(none)* | The authenticated account | Locks placed on the account itself |
| `reseller_id` | That reseller | The reseller's own locks, plus the account's |
| `organization_id` | That organization | The organization's own locks, plus its reseller's and its account's |

Use `organization_id` when deciding what to show for a specific customer — it is the only
scope that reflects the full inheritance chain. The account-level view is deliberately
coarser: it reports only the locks that reach everything beneath, because an access token
identifies an account rather than one organization.

## Query Parameters

<ParamField query="organization_id" type="string">
  Optional. Report availability for this organization, applying its account, reseller and
  organization-level locks. The organization must belong to the authenticated account, or
  the request is rejected with `404`. Mutually exclusive with `reseller_id`.
</ParamField>

<ParamField query="reseller_id" type="string">
  Optional. Report availability for this reseller, applying its own locks and those it
  inherits from the account. The reseller must belong to the authenticated account, or the
  request is rejected with `404`. Mutually exclusive with `organization_id`.
</ParamField>

<RequestExample>
  ```bash cURL theme={null}
  curl "https://api.telzino.com/v1/features" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```bash cURL (scoped to an organization) theme={null}
  curl "https://api.telzino.com/v1/features?organization_id=ORG_UUID" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```bash cURL (scoped to a reseller) theme={null}
  curl "https://api.telzino.com/v1/features?reseller_id=RESELLER_UUID" \
    -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.telzino.com/v1/features?organization_id=${orgId}`,
    { headers: { 'Authorization': 'Bearer YOUR_ACCESS_TOKEN' } }
  );

  const { data } = await response.json();

  // Hide anything this organization may not use.
  const available = new Set(
    data.filter(f => f.state === 'available').map(f => f.key)
  );
  if (available.has('knowledge_base')) showKnowledgeBaseTab();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
      'https://api.telzino.com/v1/features',
      params={'organization_id': org_id},
      headers={'Authorization': 'Bearer YOUR_ACCESS_TOKEN'},
  )

  features = response.json()['data']
  available = {f['key'] for f in features if f['state'] == 'available'}
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "feature_administration_enabled": true,
    "scope": {
      "level": "organization",
      "id": "3f2b1c9e-8a4d-4c17-9b3e-1d5a7c8e2f04"
    },
    "data": [
      {
        "key": "chat",
        "name": "Chat",
        "description": "Chat functionality for the organization.",
        "category": "CAPABILITY",
        "state": "available",
        "locked_scope": null,
        "decided_by": "feature_administration"
      },
      {
        "key": "custom_voices",
        "name": "Custom Voices",
        "description": "Allow the organization to clone and assign custom (cloned) voices for its agents.",
        "category": "CAPABILITY",
        "state": "locked",
        "locked_scope": "here",
        "decided_by": "feature_administration"
      },
      {
        "key": "integration.slack",
        "name": "Slack",
        "description": "Availability of the slack integration.",
        "category": "INTEGRATION",
        "state": "locked",
        "locked_scope": "inherited",
        "decided_by": "legacy_column"
      },
      {
        "key": "knowledge_base",
        "name": "Knowledge Base (RAG)",
        "description": "Retrieval-augmented knowledge base.",
        "category": "CAPABILITY",
        "state": "locked",
        "locked_scope": "inherited",
        "decided_by": "feature_administration"
      },
      {
        "key": "template.outbound",
        "name": "Outbound Calling Agent",
        "description": "Allow new agents that PLACE calls to be created.",
        "category": "TEMPLATE",
        "state": "available",
        "locked_scope": null,
        "decided_by": "feature_administration"
      }
    ]
  }
  ```

  ```json 400 theme={null}
  {
    "error": "invalid_request",
    "error_description": "Provide at most one of organization_id or reseller_id."
  }
  ```

  ```json 401 theme={null}
  {
    "error": "unauthorized",
    "error_description": "User payload not found"
  }
  ```

  ```json 404 theme={null}
  {
    "error": "not_found",
    "error_description": "Resource not found or access denied"
  }
  ```

  ```json 503 theme={null}
  {
    "error": "service_unavailable",
    "error_description": "Could not resolve feature availability for this scope. Please retry."
  }
  ```
</ResponseExample>

## Response Fields

| Field | Type | Description |
| - | - | - |
| `feature_administration_enabled` | boolean | Whether the feature matrix governs availability platform-wide. See [Governing regime](#governing-regime) below |
| `scope.level` | string | The level answered for: `account`, `reseller` or `organization` |
| `scope.id` | string | Identifier of the entity answered for |
| `data` | array | One entry per feature in the registry, sorted by `key` |

Each entry in `data`:

| Field | Type | Description |
| - | - | - |
| `key` | string | Stable feature identifier, e.g. `knowledge_base` or `integration.slack`. Build your checks on this, not on `name` |
| `name` | string | Display name |
| `description` | string | What the feature does, and what locking it changes |
| `category` | string | `CAPABILITY`, `TEMPLATE`, `LLM_MODEL`, `TTS`, `INTEGRATION`, `OPERATIONAL` or `COMMERCIAL`. Grouping only — it never affects access |
| `state` | string | `available` or `locked` |
| `locked_scope` | string \| null | `here` when the lock sits on the entity you asked about, `inherited` when it was placed further up the chain. `null` when the feature is available |
| `decided_by` | string | What established the answer — see below |

### `decided_by`

| Value | Meaning |
| - | - |
| `feature_administration` | The feature matrix decided, applying locks down the account → reseller → organization chain |
| `legacy_column` | A per-account or per-organization setting decided, which is what governs while Feature Administration is switched off |
| `default_available` | Nothing withholds this feature at this scope |

Integration features are the exception to the regime split: the account's integration
allow-list still applies even while Feature Administration is on, so an `integration.*`
entry can report `legacy_column` in either regime — as the example response above shows
for `integration.slack`.

### Governing regime

`feature_administration_enabled` reports which of two regimes is in force platform-wide:
the Feature Administration matrix, or the older per-account and per-organization settings
that preceded it. The same feature can be governed differently under each, so the field is
included for callers that compare responses over time or raise a support ticket about one.

It does not change how you use the response: `state` is always the answer that applies
right now, under whichever regime is active.

## Two things to build around

<Note>
  **LLM models.** An `llm.*` feature reported as `available` means the model may be assigned
  to the organization's agents; `locked` means a Partner or Reseller has withheld it. The
  always-available floor model (`gpt-4.1`) has no `llm.*` row because it can never be locked.
  The same answer, shaped for building a picker, is available from
  [`GET /v1/llm-models`](/api-reference/llm-models).
</Note>

<Note>
  **Opt-in features report permission, not state.** For `secure_access`, `phi_redaction` and
  `use_reseller_smtp`, `available` means the organization is *permitted to switch the feature
  on* — not that it currently is. Locking these prevents a new opt-in; it never turns the
  feature off for an organization already using it.
</Note>

## Errors

| Status | Meaning |
| - | - |
| `400` | Both `organization_id` and `reseller_id` were supplied, or a scope parameter was supplied with an empty value |
| `401` | Missing or invalid access token |
| `404` | The `organization_id` or `reseller_id` does not exist, or does not belong to the authenticated account |
| `503` | Availability could not be resolved. This is transient — retry. Availability is never returned partially resolved, so a `503` is returned rather than a response that under-reports locks |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.