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: “49/month platform fee,” “5,000 calls for 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
Charge types
Pricing models
The pricing model determines how the rate math works forusage 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.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:
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
0is 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
usagestrategy 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.
creditRatesonly applies whenpricingModeliscredit_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.
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 a400 with a plain-English message naming the fix:
creditPoolneeds all three numbers. A partial block (say,poolSizewithoutoverageRate) is rejected, with the missing fields named.- The numbers must make sense.
poolSizeabove zero;poolPriceandoverageRatezero or more. - Send
creditPoolORtiers, never both. Sending both would mean one of them is silently ignored, so the server refuses instead. creditPoolonly applies whenpricingModeliscredit_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
minimumCommitmenton 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:name(string) — Strategy name, e.g. “API Call Pool”agentId(UUID) — Which agent this strategy belongs tochargeType(string) - One of:usage,recurring,onetime,seat_based
signalId(UUID) — Required if chargeType isusage. The signal this strategy prices.pricingModel(string) - One of:flat,graduated,volume,credit_pool. Required forusageandseat_based.billingFrequency(string) —monthlyoryearly(default: monthly)tiers(array) — Tier configuration. Each tier haslower(number),upper(number or null),rate(number).creditPool(object) - The credit-pool shortcut:{ poolSize, poolPrice, overageRate }. Only valid whenpricingModeliscredit_pool. Compiled intotiersserver-side; send this ORtiers, never both.creditRates(object) - Which signals draw from this pool and how many credits one unit of each costs:{ signalId: creditsPerUnit }. Only valid whenpricingModeliscredit_pool. Omit it for a single-metric pool. See Letting several metrics share one pool.rate(number) — Flat rate. Used when pricingModel isflator there are no tiers.minimumCommitment(number) — Minimum units/seats to bill for, even if actual usage is lower. Not allowed oncredit_poolstrategies (the pool fee already is the minimum).active(boolean, default true) — Whether this strategy is active.tags(string[]) — Tags for categorization.
201 Created): Array of created strategies with IDs.
Using the SDK:
400 Bad Request— Missing required fields, orsignalIdnot provided for ausagestrategy. Also every credit-pool validation rejection (partialcreditPoolblock, bothcreditPoolandtierssent, a second active pool on the plan,minimumCommitmenton a pool, a degenerate tier shape, acreditRatesvalue at or below zero, acreditRateskey 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: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 (trueorfalse)page,limit— Pagination (default: page 1, limit 10)
Get a pricing strategy
Method & URL:Update a pricing strategy
Method & URL: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:Delete a pricing strategy
Method & URL:deletedAt, doesn’t destroy data).
Using the SDK:

