Advanced Pricing Models (recipes)

What this is

Copyable pricing patterns that go beyond the UI. Each recipe shows when to use it, a minimal price shape, and links to related concepts. Use these as starting points and adapt to your product.

When to use it

  • You need multi‑component pricing that the UI doesn’t support yet
  • You want hybrid models (base + usage), seat bundles, or mixed cycles
  • You need BPS‑style transaction pricing or custom minimum‑spend behavior

Recipe 1: Hybrid – base + usage with free allowance

Use when you want a predictable base fee and pay‑as‑you‑go beyond an included allowance.

Minimal price shape (trimmed)

{
  "dsl_version": 1,
  "components": [
    {
      "type": "fixed",
      "label": "Pro – Base",
      "amount_cents": 2900,
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    },
    {
      "type": "usage",
      "label": "API calls overage",
      "unit_label": "call",
      "metric_id": "met_api_calls_30d",
      "unit_cost_cents": 1,
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    }
  ]
}

How it works

  1. Create a numeric feature api-calls and metric that counts calls in the billing window. 2) Create a credit definition for the included allowance (e.g., 10,000 per month). 3) Add the usage component for overage. During billing, usage within credits is free; beyond credits is charged by this component.

Gotchas

  • Ensure the metric’s eventName matches the events you send
  • Link the credit definition to the same feature slug used by the metric
  • Keep RRULEs in UTC; avoid TZID

See also


Recipe 2: Seat‑based (per‑unit) with conceptual proration

Use when you charge per active seat/member, optionally with a minimum seat count.

Minimal price shape (trimmed)

{
  "dsl_version": 1,
  "components": [
    {
      "type": "per_unit",
      "label": "Seats",
      "unit_label": "seat",
      "amount_cents": 1000,
      "metric_id": "met_seat_count",
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    }
  ]
}

How it works

Track seats in your app (organization members) using a seat‑count metric (referenced by metric_id). Bill counting the current seat count at each cycle. If you need an included seat allowance, combine with a usage feature and credits; otherwise rely on per‑unit only.

Proration (conceptual)

Proration can be modeled by adding a one‑time fixed adjustment when seats change mid‑cycle, or by charging immediately via bill_immediately components on add‑seat flows. Exact pro‑rating rules are product‑specific.

Gotchas

  • Align UI seat count with what you bill (source of truth)
  • If you mix seats and usage, keep component cycles consistent

See also


Recipe 3: BPS on transaction volume (API)

Use when you charge a percentage of processed volume (e.g., 1%). Implement by defining a metric that sums volume in whole dollars and a usage component with per‑dollar cost equal to the percentage.

Minimal shape (trimmed)

{
  "dsl_version": 1,
  "components": [
    {
      "type": "usage",
      "label": "Processing fee (1%)",
      "unit_label": "USD",
      "metric_id": "met_volume_usd_30d",
      "unit_cost_cents": 1,
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    }
  ]
}

If your metric returns dollars, unit_cost_cents: 1 = $0.01 per $1 = 1%.

Minimum spend (advanced)

Commonly you want charge = max(minimum, bps_charge). Today this requires API‑driven adjustments (e.g., add a fixed base for the minimum and apply a plan‑level monetary credit for the difference when bps_charge exceeds the minimum). Treat this as an advanced pattern and test carefully.

Gotchas

  • Ensure the metric scales to the unit label (dollars vs cents)
  • Avoid double‑counting refunds or reversals in your event stream

See also


Recipe 4: Mixed cycles (multi‑component, different RRULEs)

Use when you need different components on different billing cycles (e.g., monthly base, yearly seat bundle, monthly usage).

Minimal shape (trimmed)

{
  "dsl_version": 1,
  "components": [
    {
      "type": "fixed",
      "label": "Base (monthly)",
      "amount_cents": 1500,
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    },
    {
      "type": "per_unit",
      "label": "Seats (yearly)",
      "unit_label": "seat",
      "amount_cents": 9000,
      "metric_id": "met_seat_count",
      "recurrence_rule": "RRULE:FREQ=YEARLY;INTERVAL=1"
    },
    {
      "type": "usage",
      "label": "AI tokens (monthly)",
      "unit_label": "1k tokens",
      "metric_id": "met_tokens_30d",
      "unit_cost_cents": 25,
      "recurrence_rule": "RRULE:FREQ=MONTHLY;INTERVAL=1"
    }
  ]
}

Each component maintains its own cycle and appears separately in subscription details and invoices.

Gotchas

  • Don’t mix timezones in RRULEs; always use pure UTC
  • Keep metric timeframes aligned to each component’s cycle when computing usage

See also


How the UI wires this

  • The Create Plan UI can scaffold usage‑based features: it creates the metric (simple COUNT/SUM from your event), creates plan‑scoped credit definitions, and when you add a usage price it links the credit definition to that usage component and aligns renewals to the billing cycle.
  • For seat‑based pricing, the UI generates a seat‑count metric and references it from per_unit components so billing reflects active seats.
  • Publishing to pricing tables is handled for you when you enable “show in pricing table”.

UI vs API

  • UI: Base fees, simple per‑unit, and standard usage patterns
  • API: BPS, minimum spend logic, mixed cycles, complex adjustments

Common pitfalls

  • Missing metric linkage for usage components → no overage computed
  • Mis‑scaled metrics (cents vs dollars) in BPS patterns
  • RRULEs with TZID or invalid cadence
  • Assuming minimum‑spend max logic exists by default — implement via API

See also