> For the complete documentation index, see [llms.txt](https://docs.hypertune.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.hypertune.com/pricing/guide.md).

# Guide

This guide builds on the SDK quickstart and shows you how to model, manage, and experiment on your pricing using Hypertune.

You'll learn how to:

* Create custom object types to model your pricing
* Create flags that use those custom object types
* Access those flags in your code
* Update your pricing
* Run experiments on your pricing

## Prerequisites

[Set up Hypertune](/getting-started/set-up-hypertune.md)

## Create custom object types to model your pricing

Go to the **Schema** view in the dashboard. Click the **+** button in the top-right of the sidebar. Select **Object**, enter a name, and click **Create**.

<figure><img src="/files/sIt7jnxE0RiUKinaF49e" alt=""><figcaption></figcaption></figure>

By default, the new object type has no fields.

Click **+ Add** to add a new field. Enter a name, select **List** from the Type dropdown, then select **New object type** from the Item type dropdown.

<figure><img src="/files/AyXRok7zfAf4XnRaUDlE" alt=""><figcaption></figcaption></figure>

Enter a name for the new type and click **Create**.

<figure><img src="/files/XSKIo3iICZ3VMM5XoLKA" alt=""><figcaption></figcaption></figure>

Repeat for each field you want to add. You can switch to the code view to make this easier. Then, click **Save**.

<figure><img src="/files/JvlpFL2QmyBZSKyCj3KR" alt=""><figcaption></figcaption></figure>

```graphql
type Pricing {
  stripePrices(plan: Plan!): [StripePrice!]!
  planContent(plan: Plan!): PlanContent!
  planFeatures: [PlanFeature!]!
  planOrdering: [Plan!]!
}

enum Plan { free, pro, enterprise }

type StripePrice {
  id: String!
  type: StripePriceType!
}

enum StripePriceType { flatFee, perSeat }

type PlanContent {
  name: String!
  description: String!
  features: [String!]!
}

type PlanFeature {
  name: String!
  value(plan: Plan!): PlanFeatureValue!
}

type PlanFeatureValue {
  isIncluded: Boolean!
  text: String!
}
```

## Create flags for your pricing

Go to the **Flags** view in the dashboard. Click the **+** button in the top-right of the sidebar and select **Flag**.

<figure><img src="/files/4BvzOLfp74h8bp0UQ9tr" alt=""><figcaption></figcaption></figure>

Enter a name, set its type to the one you created earlier, and click **Create**.

<figure><img src="/files/Z90i614EzDkyB5vRr7kQ" alt=""><figcaption></figcaption></figure>

Select the nested flag for the **Stripe Prices**, open the options (⋯) menu on the List, and select **Insert enum switch**.

<figure><img src="/files/tE495Iissj6LKvcWrBAt" alt=""><figcaption></figcaption></figure>

Set the switch Control to the **Plan** argument.

<figure><img src="/files/dYt06if5RXGAVXaTRbtf" alt=""><figcaption></figcaption></figure>

You'll see a nested sidebar item for each plan. Add the Stripe Prices for each plan. These will be added as line items when creating a Stripe checkout session.

<figure><img src="/files/yY4jL3EBVg8wDAska5Pp" alt=""><figcaption></figcaption></figure>

Insert an enum switch on the **Plan Content** flag, and add content for each plan. This will be used to render the plans table that lets your users compare each plan.

<figure><img src="/files/WPeUtGLplCLdrtztQ1SC" alt=""><figcaption></figcaption></figure>

Select the **Plan Features** list flag. This will be used to render the detailed features table under the plans table.

Add a Plan Feature, enter a name for it, then select **Insert enum switch** on the value field.

<figure><img src="/files/MdVq6yvsGniYuwNGDeRx" alt=""><figcaption></figcaption></figure>

This lets you return different values for each plan.

<figure><img src="/files/9ifbcVMKreM6gG6mqeCM" alt=""><figcaption></figcaption></figure>

Repeat for all the features you want to show in your features table.

Finally, select the **Plan Ordering** flag, set the order that plans should appear in the plans table and features table, and click **Save**.

<figure><img src="/files/hSqyoKaOFOAwOZG9Smfq" alt=""><figcaption></figcaption></figure>

## Access flags to retrieve pricing

Regenerate the client:

{% tabs %}
{% tab title="npm" %}

```bash
npx hypertune
```

{% endtab %}

{% tab title="yarn" %}

```bash
yarn hypertune
```

{% endtab %}

{% tab title="pnpm" %}

```bash
pnpm hypertune
```

{% endtab %}
{% endtabs %}

Then use the generated methods for your flags to get the pricing configuration when creating Stripe checkout sessions and rendering pricing components:

{% code title="api/upgrade/route.ts" %}

```typescript
import { waitUntil } from '@vercel/functions'
import { NextResponse } from 'next/server'
import getHypertune from '@/lib/getHypertune'
import getStripe from '@/lib/getStripe'
import getTeamSize from '@/lib/getTeamSize'

export const runtime = 'edge'

export async function POST(request: Request) {
  const hypertune = await getHypertune({ isRouteHandler: true })

  const stripePrices = hypertune
    .pricing()
    .stripePrices({ args: { plan: 'pro' } })
    .map((price) => price.get())

  const teamSize = getTeamSize()

  const lineItems = stripePrices.map((price) => ({
    price: price.id,
    quantity: price.type === 'perSeat' ? teamSize : 1,
  }))

  const stripe = getStripe()

  const baseUrl = new URL(request.url).origin

  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    line_items: lineItems,
    success_url: `${baseUrl}/success`,
    cancel_url: `${baseUrl}/cancel`,
  })

  waitUntil(hypertune.flushLogs())

  return NextResponse.json({
    sessionUrl: session.url,
    sessionId: session.id,
  })
}
```

{% endcode %}

{% code title="components/Pricing.tsx" %}

```tsx
import FeaturesTable from './FeaturesTable'
import PlansTable from './PlansTable'
import getHypertune from '@/lib/getHypertune'

export default async function Pricing() {
  const hypertune = await getHypertune()
  const pricing = hypertune.pricing()

  return (
    <div className="pricing">
      <h2>Pricing</h2>
      <PlansTable pricing={pricing} />
      <FeaturesTable pricing={pricing} />
    </div>
  )
}
```

{% endcode %}

{% code title="components/PlansTable.tsx" %}

```tsx
import {
  type PricingNode,
  type PlanContentNode,
} from '@/generated/hypertune'

export default function PlansTable({
  pricing,
}: {
  pricing: PricingNode
}) {
  const planOrdering = pricing.planOrdering({
    itemFallback: 'free',
  })

  return (
    <div className="plans-table">
      {planOrdering.map((plan) => {
        const planContent = pricing.planContent({
          args: { plan },
        })
        return (
          <PlanColumn key={plan} planContent={planContent} />
        )
      })}
    </div>
  )
}

function PlanColumn({
  planContent,
}: {
  planContent: PlanContentNode
}) {
  const content = planContent.get()

  return (
    <div className="plan-column">
      <h3>{content.name}</h3>
      <p>{content.description}</p>
      <ul>
        {content.features.map((feature) => (
          <li key={feature}>{feature}</li>
        ))}
      </ul>
    </div>
  )
}
```

{% endcode %}

{% code title="components/FeaturesTable.tsx" %}

```tsx
import { type PricingNode } from '@/generated/hypertune'

export default function FeaturesTable({
  pricing,
}: {
  pricing: PricingNode
}) {
  const planOrdering = pricing.planOrdering({
    itemFallback: 'free',
  })
  const planFeatures = pricing.planFeatures()

  return (
    <table className="features-table">
      <thead>
        <tr>
          <th>Feature</th>
          {planOrdering.map((plan) => (
            <th key={plan}>{plan}</th>
          ))}
        </tr>
      </thead>
      <tbody>
        {planFeatures.map((feature) => {
          const featureName = feature.name({
            args: {},
            fallback: '',
          })
          return (
            <tr key={featureName}>
              <td>{featureName}</td>
              {planOrdering.map((plan) => {
                const value = feature
                  .value({ args: { plan } })
                  .get()
                return (
                  <td key={plan}>
                    {value.text ? (
                      <span className="text">{value.text}</span>
                    ) : value.isIncluded ? (
                      <span className="tick">✓</span>
                    ) : (
                      <span className="cross">✗</span>
                    )}
                  </td>
                )
              })}
            </tr>
          )
        })}
      </tbody>
    </table>
  )
}
```

{% endcode %}

## Update your pricing configuration

Go to the **Flags** view in the dashboard, expand the top-level flag with your pricing configuration in the left sidebar, and select the nested flag that you want to configure.

<figure><img src="/files/auUJ6qJ8vF39aaykQDAm" alt=""><figcaption></figcaption></figure>

Make your changes, then open the **Diff** view to review them. Click **Save**.

<figure><img src="/files/9ogWnU2lHr8uWWJiHNZ1" alt=""><figcaption></figcaption></figure>

## Add a new plan

Go to the **Schema** view in the dashboard, select the **Plan** enum, and add a value for the new plan.

<figure><img src="/files/lY2DFxX42wLVV1sVivZx" alt=""><figcaption></figcaption></figure>

Go to the **Flags** view, and enter the configuration for the new plan across each of your nested flags for the **Stripe Prices**, **Plan Content**, **Plan Features**, and **Plan Ordering**.

<figure><img src="/files/xwFS4os4w6EOdnMJ4FRC" alt=""><figcaption></figcaption></figure>

## A/B test a new plan

To measure the impact of the new plan on conversion and revenue, select the **Plan Ordering** flag.

<figure><img src="/files/CHXSxtxmqGsoJRWDUOzO" alt=""><figcaption></figcaption></figure>

Click **+ Experiment**, select **New experiment** from the dropdown, enter a name for it, click **Create**, then click **Insert**.

In the Test Variant, replace the old plan enum value with the new one you created earlier.

<figure><img src="/files/8eTJHFCvGPOiAwYf5OcN" alt=""><figcaption></figcaption></figure>

## Next steps

* Build an [impact analysis](/concepts/impact-analyses.md) or [funnel](/concepts/funnels.md) to view the performance of each experiment variant.
* Experiment on your plan content and plan features.
