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

# Custom Plans

> Gate features for users who built their own plan

When a user builds a custom plan by picking individual features, the receipt metadata contains the feature details directly.

## How metadata is stored

Stripe limits metadata values to 500 characters. Cuprice splits the feature JSON across multiple keys:

```json theme={null}
{
  "customPlan": "true",
  "featureDetails_0": "[{\"name\":\"AI Prompt\",\"type\":\"Standard\",\"price\":10},",
  "featureDetails_1": "{\"name\":\"Dashboard\",\"type\":\"Standard\",\"price\":20}]"
}
```

## Reconstructing the feature list

Join all `featureDetails_*` keys and parse the JSON:

```typescript theme={null}
const metadata = receipt.metadata;

let json = "";
Object.keys(metadata)
  .filter(k => k.startsWith("featureDetails"))
  .sort()
  .forEach(k => json += metadata[k]);

const features = JSON.parse(json);
// => [{ name: "AI Prompt", type: "Standard", price: 10 }, ...]
```

## Feature object shape

Each feature in the array has:

<ResponseField name="name" type="string" required>
  Feature name (e.g. "AI Prompt")
</ResponseField>

<ResponseField name="type" type="string" required>
  Feature type: "Standard", "Limits", or "Usage Based"
</ResponseField>

<ResponseField name="price" type="number" required>
  Price for this feature
</ResponseField>

<ResponseField name="quantity" type="number">
  For Limits/Usage Based features, the purchased quantity
</ResponseField>
