# Plan Fit: Usage-Based API

> A speech-to-text API billed by audio hours, with yearly billing. Build sells extra hours in packs, so it stays the best fit well past its 100 hours, until Scale costs less.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/plan-fit-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/plan-fit-demo
- Screenshot: https://shadcn.exchange/shot/keyframeui/plan-fit-demo/light.png
- Registry item: https://keyframeui.com/r/plan-fit-demo.json
- Categories: pricing, interaction, data
- Listed: 2026-11-02, source last changed 2026-11-02

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/keyframeui/plan-fit-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/plan-fit.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/plan-fit#plan-fit-demo

## Files

### `registry/demos/plan-fit-demo.tsx`

```tsx
"use client";

import { PlanFit, type PlanFitBilling, type PlanFitPlan } from "@/components/ui/plan-fit";

// A speech-to-text API billed by hours of audio. Build sells extra hours in
// packs, so it stays the cheapest well past its 100 hours, until Scale wins.
const PLANS: PlanFitPlan[] = [
  {
    id: "free",
    name: "Free",
    pitch: "Try it on your own recordings.",
    price: 0,
    included: 5,
    caption: "No card needed",
    features: ["English and Spanish", "Speaker labels", "Community forum"],
    cta: { label: "Start free", href: "#start" },
  },
  {
    id: "build",
    name: "Build",
    pitch: "For apps shipping their first voice feature.",
    price: { monthly: 29, yearly: 23 },
    included: 100,
    overage: { price: 4, per: 10 },
    caption: { monthly: "Billed monthly", yearly: "Billed $276 a year" },
    features: ["40 languages", "Word-level timestamps", "Email support"],
    cta: { label: "Start building", href: "#build" },
  },
  {
    id: "scale",
    name: "Scale",
    pitch: "For products people talk to every day.",
    price: { monthly: 249, yearly: 199 },
    included: 1000,
    overage: { price: 30, per: 100 },
    limit: 2500,
    caption: { monthly: "Billed monthly", yearly: "Billed $2,388 a year" },
    features: ["Live streaming", "Custom vocabulary", "99.9% uptime SLA"],
    cta: { label: "Choose Scale", href: "#scale" },
  },
  {
    id: "enterprise",
    name: "Enterprise",
    pitch: "Dedicated capacity in your own region.",
    price: "Custom",
    caption: "Volume pricing",
    features: ["On-prem or your VPC", "A named engineer", "Signed DPA and SOC 2"],
    cta: { label: "Talk to sales", href: "#sales" },
  },
];

const BILLING: PlanFitBilling[] = [
  { id: "monthly", label: "Monthly" },
  { id: "yearly", label: "Yearly", note: "−20%" },
];

export function PlanFitDemo() {
  return (
    <div className="w-full max-w-5xl">
      <PlanFit
        plans={PLANS}
        unit="hours"
        readoutLabel="hours of audio transcribed per month"
        defaultValue={60}
        max={5000}
        billing={BILLING}
        defaultBilling="monthly"
      />
    </div>
  );
}
```
