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

# Pricing

> Monthly subscription plans and pricing for the Zerion API

export const PricingCalculator = () => {
  const monthlyStops = [0, 60000, 250000, 1000000, 3000000]
  const rpsStops = [0, 50, 150, 300, 1000]
  const plans = [
    {
      name: "Developer",
      price: 0,
      monthlyLimit: 60000,
      rps: 10,
      description: "For early prototypes and proofs of concept",
    },
    {
      name: "Builder",
      price: 149,
      monthlyLimit: 250000,
      rps: 50,
      description: "For shipping MVPs without running any infra",
    },
    {
      name: "Startup",
      price: 499,
      monthlyLimit: 1000000,
      rps: 150,
      description: "For apps preparing for launch or in production",
    },
    {
      name: "Growth",
      price: 999,
      monthlyLimit: 2500000,
      rps: 300,
      description: "For scaling products with growing traffic demands",
    },
    {
      name: "Enterprise",
      price: null,
      monthlyLimit: 2500001,
      rps: 1000,
      description: "For scale-ups and enterprises with high volume or custom needs",
    },
  ]

  const sliderSegments = 4
  const sliderStep = 0.001

  const roundToIncrement = (value, increment) => Math.round(value / increment) * increment

  const valueToSliderPosition = (value, stops) => {
    for (let index = 0; index < stops.length - 1; index += 1) {
      const start = stops[index]
      const end = stops[index + 1]

      if (value <= end) {
        const segmentProgress = end === start ? 0 : (value - start) / (end - start)
        return index + segmentProgress
      }
    }

    return stops.length - 1
  }

  const sliderPositionToValue = (position, stops) => {
    const safePosition = Math.max(0, Math.min(stops.length - 1, position))
    const index = Math.min(Math.floor(safePosition), stops.length - 2)
    const start = stops[index]
    const end = stops[index + 1]
    const segmentProgress = safePosition - index

    return Math.round(start + (end - start) * segmentProgress)
  }

  const smoothMonthlyCalls = (value) => {
    if (value <= 60000) return roundToIncrement(value, 1000)
    if (value <= 250000) return roundToIncrement(value, 5000)
    if (value <= 1000000) return roundToIncrement(value, 10000)
    return roundToIncrement(value, 25000)
  }

  const smoothPeakRps = (value) => {
    if (value <= 150) return roundToIncrement(value, 1)
    if (value <= 300) return roundToIncrement(value, 5)
    return roundToIncrement(value, 10)
  }

  const [callsSliderPosition, setCallsSliderPosition] = React.useState(
    valueToSliderPosition(100000, monthlyStops)
  )
  const [rpsSliderPosition, setRpsSliderPosition] = React.useState(
    valueToSliderPosition(25, rpsStops)
  )

  const monthlyCalls = smoothMonthlyCalls(
    sliderPositionToValue(callsSliderPosition, monthlyStops)
  )
  const peakRps = smoothPeakRps(sliderPositionToValue(rpsSliderPosition, rpsStops))
  const isEnterprise = monthlyCalls > 2500000 || peakRps > 300

  const formatNumber = (value) => {
    if (value >= 1000000) {
      return `${(value / 1000000).toFixed(1).replace(/\.0$/, "")}M`
    }

    if (value >= 1000) {
      return `${Math.round(value / 1000)}K`
    }

    return `${value}`
  }

  const recommendedPlan =
    plans.find((plan) => monthlyCalls <= plan.monthlyLimit && peakRps <= plan.rps) ||
    plans[plans.length - 1]
  const callsProgress = `${(callsSliderPosition / sliderSegments) * 100}%`
  const rpsProgress = `${(rpsSliderPosition / sliderSegments) * 100}%`

  const priceLabel =
    recommendedPlan.price === null
      ? "Custom"
      : recommendedPlan.price === 0
        ? "Free"
        : `$${recommendedPlan.price}`

  const ctaLabel =
    recommendedPlan.price === null
      ? "Contact us"
      : recommendedPlan.price === 0
        ? "Get started free"
        : "Get started"

  return (
    <div className="not-prose space-y-4">
      <div className="grid gap-3 lg:grid-cols-2">
        <div className="rounded-2xl border border-zinc-200 dark:border-white/10 p-4 space-y-3">
          <div className="flex items-center justify-between gap-3">
            <div className="text-sm font-medium text-zinc-900 dark:text-white">
              Monthly API calls
            </div>
            <div className="rounded-lg bg-indigo-700 px-3 py-1 text-sm font-semibold text-white min-w-[4.5rem] text-center">
              {monthlyCalls >= 3000000 ? "3M+" : formatNumber(monthlyCalls)}
            </div>
          </div>

          <div className="relative">
            <input
              type="range"
              min="0"
              max={sliderSegments}
              step={sliderStep}
              value={callsSliderPosition}
              onChange={(e) => setCallsSliderPosition(Number.parseFloat(e.target.value))}
              className="pricing-slider cursor-pointer"
              style={{ "--slider-progress": callsProgress }}
            />

            <div className="mt-2 flex justify-between text-[11px] text-zinc-500 dark:text-white/50">
              <span>0</span>
              <span>60K</span>
              <span>250K</span>
              <span>1M</span>
              <span>3M+</span>
            </div>
          </div>
        </div>

        <div className="rounded-2xl border border-zinc-200 dark:border-white/10 p-4 space-y-3">
          <div className="flex items-center justify-between gap-3">
            <div className="text-sm font-medium text-zinc-900 dark:text-white">
              Peak requests per second
            </div>
            <div className="rounded-lg bg-indigo-700 px-3 py-1 text-sm font-semibold text-white min-w-[4.5rem] text-center">
              {peakRps >= 1000 ? "1000+" : peakRps}
            </div>
          </div>

          <div className="relative">
            <input
              type="range"
              min="0"
              max={sliderSegments}
              step={sliderStep}
              value={rpsSliderPosition}
              onChange={(e) => setRpsSliderPosition(Number.parseFloat(e.target.value))}
              className="pricing-slider cursor-pointer"
              style={{ "--slider-progress": rpsProgress }}
            />

            <div className="mt-2 flex justify-between text-[11px] text-zinc-500 dark:text-white/50">
              <span>0</span>
              <span>50</span>
              <span>150</span>
              <span>300</span>
              <span>1000+</span>
            </div>
          </div>
        </div>
      </div>

      <div className="rounded-2xl border-2 border-indigo-700 bg-indigo-50/70 dark:bg-indigo-500/10 p-4 flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
        <div className="space-y-2">
          <div className="text-xs font-bold tracking-[0.18em] text-indigo-700 dark:text-indigo-300">
            RECOMMENDED PLAN
          </div>
          <div className="text-2xl font-bold text-zinc-950 dark:text-white">
            {recommendedPlan.name}
          </div>
          <div className="text-sm text-zinc-600 dark:text-white/70">
            {recommendedPlan.description}
          </div>
          <div className="text-xs text-zinc-500 dark:text-white/50">
            Sized for {formatNumber(monthlyCalls)} monthly calls and {peakRps} peak RPS
          </div>
        </div>

        <div className="text-left md:text-right space-y-1.5">
          <div className="text-3xl font-extrabold text-indigo-700 dark:text-indigo-300">
            {priceLabel}
          </div>
          {recommendedPlan.price !== null && (
            <div className="text-sm text-zinc-600 dark:text-white/70">per month</div>
          )}
          <a
            href="https://dashboard.zerion.io/"
            target="_blank"
            rel="noopener"
            className="inline-flex rounded-lg bg-indigo-700 px-4 py-2 text-sm font-semibold text-white no-underline"
          >
            {ctaLabel}
          </a>
        </div>
      </div>

      <div className="grid gap-2 md:grid-cols-2 xl:grid-cols-5">
        {plans.map((plan) => {
          const isRecommended = plan.name === recommendedPlan.name
          const isTooSmall =
            (plan.monthlyLimit < monthlyCalls || plan.rps < peakRps) &&
            plan.name !== "Enterprise"
          const planPrice =
            plan.price === null ? "Custom" : plan.price === 0 ? "Free" : `$${plan.price}/mo`

          return (
            <div
              key={plan.name}
              className={`rounded-xl p-4 relative ${
                isRecommended
                  ? "border-2 border-indigo-700 bg-indigo-50/60 dark:bg-indigo-500/10"
                  : "border border-zinc-200 dark:border-white/10"
              } ${isTooSmall ? "opacity-40" : "opacity-100"}`}
            >
              {isRecommended && (
                <div className="absolute -top-3 left-3 rounded bg-indigo-700 px-2 py-1 text-[10px] font-bold tracking-[0.12em] text-white">
                  BEST FIT
                </div>
              )}
              <div className="mb-1 text-sm font-bold text-zinc-950 dark:text-white">
                {plan.name}
              </div>
              <div className="mb-2 text-base font-bold text-indigo-700 dark:text-indigo-300">
                {planPrice}
              </div>
              <div className="space-y-1 text-xs text-zinc-600 dark:text-white/70">
                <div>
                  {plan.name === "Enterprise"
                    ? "2.5M+ calls/mo"
                    : `${formatNumber(plan.monthlyLimit)} calls/mo`}
                </div>
                <div>{plan.rps >= 1000 ? "1,000+" : plan.rps} RPS</div>
              </div>
            </div>
          )
        })}
      </div>

      <div className="text-xs text-zinc-500 dark:text-white/50">
        Developer is limited to 2,000 calls/day, about 60K/month. Enterprise pricing is custom.
      </div>
    </div>
  )
}

Zerion API pricing is based on monthly subscription plans with fixed limits on monthly calls and peak requests per second. This makes costs easy to predict and plan.

## Estimate your cost

<PricingCalculator />
