Skip to main content

Pricing Strategies

A pricing strategy is the actual pricing rule inside a plan. If a pricing plan is the “Pro Plan” container, strategies are the line items: “0.01perAPIcall,""0.01 per API call," "49/month platform fee,” “5,000 calls for 99then99 then 0.03 overage.” A plan can have multiple strategies. Most plans combine a few:
  • A usage strategy for per-event billing (tied to a signal)
  • A recurring strategy for a fixed monthly fee
  • A onetime strategy for a setup fee
  • A seat_based strategy for per-user pricing
Each strategy has a charge type (what kind of charge) and a pricing model (how the math works).

Charge types


Pricing models

The pricing model determines how the rate math works for usage and seat_based strategies.

Flat

Every unit costs the same price. Simple multiplication.

Graduated

Different rates for different quantity ranges — like tax brackets. Each range is charged at its own rate.

Volume

Total quantity determines ONE rate for ALL units. The more you use, the cheaper each unit gets — but the rate applies to everything, not just the overflow.

Credit Pool

Flat fee for a pool of units, then per-unit overage. You pay the pool price whether you use 1 unit or all of them. Only after exceeding the pool does the overage rate kick in.
Tier layout for credit pool:
The first tier’s rate is the flat pool price (not per-unit). The second tier’s rate is the per-unit overage rate. That asymmetry is easy to get backwards, so you don’t have to build it. Send a creditPool block instead and the server compiles the tiers for you:
poolSize is how many units the pool covers each cycle, poolPrice is the flat fee charged every cycle whether or not it’s used, and overageRate is the per-unit price after the pool runs out. Nothing stops when the pool empties; the overage keeps billing. Every strategy you read back also carries a derived creditPool field with the same three numbers (null on non-pool strategies, and on any pool whose stored tiers aren’t a clean two-tier shape).

Letting several metrics share one pool (creditRates)

By default a pool counts one signal: the one you priced, at one credit per unit. creditRates opens the pool to other signals and says how many credits each one costs:
One report takes 4 credits out of the pool, one video takes 10, and two notes take 1. All of them draw the same balance, so the customer still watches one number. The pool bills off the combined credit total, and a member signal never gets its own separate line on the invoice. Rules, each of them a 400 with a message naming the fix:
  • Every value must be a number above zero. To make a metric free, leave it out of the map. A 0 is refused rather than honored, because it usually means a field someone forgot to fill in.
  • Every key must be a live signal in your organization. A mistyped or deleted ID is refused instead of sitting in the map matching nothing.
  • A signal can burn pool credits or bill per unit, never both. If a key names a signal that also has its own active usage strategy on the same plan, the write is refused: the customer would pay twice for one unit of work. This is checked against the whole plan, so turning on a competing usage strategy later is refused the same way.
  • The pool’s own signal is a member whether or not you name it, at rate 1. Name it only to change that.
  • creditRates only applies when pricingModel is credit_pool. Clear the rates (creditRates: {}) in the same update if you’re moving the strategy to another model.
  • Send {} to clear every rate. Omit the field to leave the stored rates alone.
A pool with no creditRates behaves exactly as it always has. The balance fields keep their ...Units names either way; once rates are on, read “unit” as “credit.”

Credit-pool validation rules

The server validates every write that touches a credit pool (create, update, and both bulk lanes), evaluated against the merged result of what’s stored plus your patch. Each rejection comes back as a 400 with a plain-English message naming the fix:
  • creditPool needs all three numbers. A partial block (say, poolSize without overageRate) is rejected, with the missing fields named.
  • The numbers must make sense. poolSize above zero; poolPrice and overageRate zero or more.
  • Send creditPool OR tiers, never both. Sending both would mean one of them is silently ignored, so the server refuses instead.
  • creditPool only applies when pricingModel is credit_pool.
  • One active credit pool per plan. A write that would leave a plan with two live pools is rejected. The ledger counts down ONE pool per plan, so a second pool would make the countdown ambiguous. Put it on its own plan.
  • No minimumCommitment on a credit pool. The pool fee already is the minimum the customer pays every cycle.
  • Hand-built tiers are shape-checked too. The pool tier must start at 0 with an upper bound above zero; the overage tier must start exactly where the pool ends and have no ceiling (upper: null).

Create pricing strategies (bulk)

In plain English: Add one or more pricing strategies to a plan. You can create all your strategies in one call — send an array. Method & URL:
The request body is an array of strategies (even if you’re only creating one). Required fields per strategy:
  • name (string) — Strategy name, e.g. “API Call Pool”
  • agentId (UUID) — Which agent this strategy belongs to
  • chargeType (string) - One of: usage, recurring, onetime, seat_based
Optional fields:
  • signalId (UUID) — Required if chargeType is usage. The signal this strategy prices.
  • pricingModel (string) - One of: flat, graduated, volume, credit_pool. Required for usage and seat_based.
  • billingFrequency (string)monthly or yearly (default: monthly)
  • tiers (array) — Tier configuration. Each tier has lower (number), upper (number or null), rate (number).
  • creditPool (object) - The credit-pool shortcut: { poolSize, poolPrice, overageRate }. Only valid when pricingModel is credit_pool. Compiled into tiers server-side; send this OR tiers, never both.
  • creditRates (object) - Which signals draw from this pool and how many credits one unit of each costs: { signalId: creditsPerUnit }. Only valid when pricingModel is credit_pool. Omit it for a single-metric pool. See Letting several metrics share one pool.
  • rate (number) — Flat rate. Used when pricingModel is flat or there are no tiers.
  • minimumCommitment (number) — Minimum units/seats to bill for, even if actual usage is lower. Not allowed on credit_pool strategies (the pool fee already is the minimum).
  • active (boolean, default true) — Whether this strategy is active.
  • tags (string[]) — Tags for categorization.
Example — create three strategies in one call:
What you get back (201 Created): Array of created strategies with IDs. Using the SDK:
For a credit pool on its own there’s a one-call shortcut that fills in the charge type and pricing model for you:
Common errors:
  • 400 Bad Request — Missing required fields, or signalId not provided for a usage strategy. Also every credit-pool validation rejection (partial creditPool block, both creditPool and tiers sent, a second active pool on the plan, minimumCommitment on a pool, a degenerate tier shape, a creditRates value at or below zero, a creditRates key that isn’t a live signal, or a signal that would both burn credits and bill per unit); the message names the exact rule and the fix.
  • 404 Not Found — Plan, agent, or signal not found in this org.

List pricing strategies

Method & URL:
Query parameters:
  • chargeType - Filter by charge type (usage, recurring, onetime, seat_based)
  • pricingModel — Filter by pricing model (flat, graduated, volume, credit_pool)
  • active — Filter by active status (true or false)
  • page, limit — Pagination (default: page 1, limit 10)
Using the SDK:

Get a pricing strategy

Method & URL:
Using the SDK:

Update a pricing strategy

Method & URL:
All fields are optional. Only send what you want to change. Example — change the overage rate on a credit pool strategy:
Using the SDK:

Bulk update + create

In plain English: Update existing strategies and create new ones in a single call. Useful when reconfiguring an entire plan. Method & URL:
Request body:

Delete a pricing strategy

Method & URL:
Soft-delete (sets deletedAt, doesn’t destroy data). Using the SDK:

How strategies fit in the billing chain