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

# Plans

> Segment users and accounts by their commercial plan.

## Overview

`plans` is a **reserved structured attribute** on every account. It lets you
natively segment and filter both users and accounts by their commercial plan
(trial, paid tiers, billing cadence) without ad-hoc queries or manual tagging.

Because a user can belong to multiple accounts, plan data is also denormalized
onto each user, so user-level filtering stays fast.

## The `PlanItem` contract

An account's `plans` is an array of plan objects:

| Field      | Type   | Required | Notes                                                                         |
| ---------- | ------ | -------- | ----------------------------------------------------------------------------- |
| `key`      | string | **Yes**  | Free-form identifier, stored lowercased. Used for filtering and segmentation. |
| `label`    | string | **Yes**  | Human-readable display name.                                                  |
| `period`   | string | No       | One of `daily`, `weekly`, `monthly`, `yearly`, `custom`.                      |
| `price`    | number | No       | Must be ≥ 0.                                                                  |
| `currency` | string | No       | ISO 4217 code (e.g. `USD`). **Required when `price` is set.**                 |

```json theme={null}
{
  "plans": [
    { "key": "trial", "label": "Trial" },
    { "key": "pro", "label": "Pro Monthly", "period": "monthly", "price": 49, "currency": "USD" }
  ]
}
```

Plan keys are deduplicated per account — sending the same `key` twice keeps the
last occurrence. Values are normalized and validated server-side regardless of
the write channel.

## A reserved attribute

`plans` is reserved: it is always written into the typed `account.plans` field
and **never** into the generic custom-attributes map. An `identify` or API
caller cannot smuggle arbitrary structure into it.

<Note>
  `plan` (singular string) is a **legacy** field, now **deprecated in favour of
  `plans`**. It is left untouched for backwards compatibility — new integrations
  should use `plans` only.
</Note>

## Setting plans

Plans can be set through two channels:

* **SDK `identify`** — via the `account.plans` array. See [identify](/sdk/identify).
* **Server API** — via the account upsert endpoint, or `PATCH /accounts/:id`
  from the workspace.

In all cases, sending `plans` **replaces** the account's plan list. An empty
array (`[]`) **clears** all plans; omitting `plans` leaves them **unchanged**.

```javascript theme={null}
Hacktionbase.identify({
  id: 'user_123',
  account: {
    id: 'org_456',
    plans: [{ key: 'pro', label: 'Pro' }],
  },
});
```

## Filtering and segmentation

| Surface                      | Behaviour                                                                                                          |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **Plan facet**               | A "Plan" filter appears in the Users and Accounts side filters.                                                    |
| `GET /accounts/facets/plans` | Returns distinct plan keys with their label and account count.                                                     |
| `GET /accounts?planKey=…`    | Filters accounts carrying that plan key.                                                                           |
| `GET /users?planKey=…`       | Filters users — **ANY** match: a user is returned if at least one of its accounts carries that plan key.           |
| **Segments**                 | `Plan` is available as a condition attribute for **user** segments. Account-entity segments are not yet supported. |

## User cache

Each user caches the plan data of every account it belongs to:

* `cache.accounts[].plans` — the full plan objects, per associated account.
* `cache.planKeys` — the flattened, deduplicated union of plan keys across all
  of the user's accounts. This is the field queried for user-level filtering.

Caches are recomputed **synchronously** on every account write — there is no
background sync, so plan filters never read stale data.
