Pricing Models & SLAs
Tools advertise prices in their signed manifests. Authorities issue budgets on capability tokens. The kernel runs at dispatch time and decides whether the budget covers the next call at the advertised price. For tools that need pre-execution reservation or post-execution settlement, a metered billing block on the governed transaction intent ties the call to a quote with an explicit settlement posture.
The Four Pricing Models
The PricingModel enum in chio-manifest has four variants. The wire spelling is snake_case.
| Variant | Wire name | Behavior |
|---|---|---|
PricingModel::Flat | flat | One fixed base price; no parameter sensitivity. |
PricingModel::PerInvocation | per_invocation | Same fixed unit price every call; billing unit is invocation. |
PricingModel::PerUnit | per_unit | Price scales with a declared billing unit such as 1k_tokens, MB, or row. |
PricingModel::Hybrid | hybrid | Fixed base plus a per-unit variable component. |
All prices are denominated in minor currency units (cents for USD, the smallest denomination for other currencies), matching the MonetaryAmount type from chio-core-types::capability.
pub struct MonetaryAmount {
/// Amount in the currency's smallest unit (e.g. cents for USD).
pub units: u64,
/// ISO 4217 currency code. Examples: "USD", "EUR", "JPY".
pub currency: String,
}ToolPricing
Each ToolDefinition in a manifest may carry an optional ToolPricing block. The fields are flat:
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ToolPricing {
pub pricing_model: PricingModel,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub base_price: Option<MonetaryAmount>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub unit_price: Option<MonetaryAmount>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub billing_unit: Option<String>,
}Which fields are populated depends on the model:
| Model | base_price | unit_price | billing_unit |
|---|---|---|---|
flat | Set | Absent | Absent or invocation |
per_invocation | Absent | Set | invocation |
per_unit | Absent | Set | Names the scaling dimension |
hybrid | Set | Set | Names the scaling dimension |
{
"name": "summarize",
"description": "Returns a model-generated summary",
"input_schema": { "...": "..." },
"pricing": {
"pricing_model": "hybrid",
"base_price": { "units": 100, "currency": "USD" },
"unit_price": { "units": 5, "currency": "USD" },
"billing_unit": "1k_tokens"
},
"has_side_effects": false,
"latency_hint": "moderate"
}No SLA fields on ToolPricing
ToolPricing struct in chio-manifest does not include SLA guarantees, currency caps, or per-call ceilings. Those values live on the marketplace listing (ListingSla,ListingPricingHint) or on the capability grant (max_cost_per_invocation,max_total_cost) rather than the manifest pricing block.SLA on Marketplace Listings
Service-level commitments live on the marketplace listing, signed by the operator and paired with a price hint. The struct is ListingSla in chio-listing::discovery:
pub struct ListingSla {
pub max_latency_ms: u64,
/// Availability SLA in basis points. 10_000 = 100.00%.
pub availability_bps: u32,
pub throughput_rps: u64,
}The signed pricing hint ListingPricingHint attaches one SLA, one price-per-call, and a recent-activity snapshot to a published listing:
pub struct ListingPricingHint {
pub schema: String, // chio.marketplace.listing-pricing-hint.v1
pub listing_id: String,
pub namespace: String,
pub provider_operator_id: String,
pub capability_scope: String,
pub price_per_call: MonetaryAmount,
pub sla: ListingSla,
/// Rolling revocation rate over recent invocations, in basis points.
pub revocation_rate_bps: u32,
/// Number of receipts the provider has produced in the recent window.
pub recent_receipts_volume: u64,
pub issued_at: u64,
pub expires_at: u64,
}Validation rules from ListingPricingHint::validate and ListingSla::validate:
price_per_call.units > 0; a zero-unit price is rejected.revocation_rate_bpsMUST sit in[0, 10000].expires_at > issued_at; past-expiry hints are stale and the listing falls out of the marketplace.availability_bpsMUST sit in(0, 10000].max_latency_msandthroughput_rpsMUST be greater than zero.
Metered Billing on the Governed Intent
For tools where the cost depends on something the kernel cannot see ahead of time (token counts, transferred bytes, outbound third-party fees), the agent attaches a MeteredBillingContext to its GovernedTransactionIntent. This binds the call to a quote from a billing or metering provider with an explicit settlement posture.
pub struct GovernedTransactionIntent {
pub id: String,
pub server_id: String,
pub tool_name: String,
pub purpose: String,
pub max_amount: Option<MonetaryAmount>,
pub commerce: Option<GovernedCommerceContext>,
pub metered_billing: Option<MeteredBillingContext>,
pub runtime_attestation: Option<RuntimeAttestationEvidence>,
pub call_chain: Option<GovernedCallChainContext>,
pub autonomy: Option<GovernedAutonomyContext>,
pub context: Option<serde_json::Value>,
}
pub struct MeteredBillingContext {
pub settlement_mode: MeteredSettlementMode,
pub quote: MeteredBillingQuote,
/// Optional explicit upper bound on billable units for the request.
pub max_billed_units: Option<u64>,
}MeteredSettlementMode
| Variant | Wire name | Posture |
|---|---|---|
MustPrepay | must_prepay | Action MUST NOT execute unless the quoted amount is prepaid. |
HoldCapture | hold_capture | Action MAY execute against a hold and settle later via capture or release. |
AllowThenSettle | allow_then_settle | Action MAY execute first and settle later with truthful pending state. |
MeteredBillingQuote
pub struct MeteredBillingQuote {
/// Stable quote identifier from the billing or metering authority.
pub quote_id: String,
/// Billing or metering provider that issued the quote.
pub provider: String,
/// Billing unit used to interpret quoted_units (e.g. 1k_tokens).
pub billing_unit: String,
/// Quoted number of billable units for the pre-execution estimate.
pub quoted_units: u64,
/// Quoted monetary amount for the estimate.
pub quoted_cost: MonetaryAmount,
/// Unix timestamp (seconds) when the quote was issued.
pub issued_at: u64,
/// Optional Unix timestamp (seconds) when the quote expires.
pub expires_at: Option<u64>,
}
impl MeteredBillingQuote {
pub fn is_valid_at(&self, now: u64) -> bool {
now >= self.issued_at
&& self.expires_at.is_none_or(|expires_at| now < expires_at)
}
}Quote Validity Windows
The kernel calls is_valid_at(now) before applying the quote. Quotes with no expires_at remain valid indefinitely (subject to the issuing provider's revocation), but a quote with an expiry that has passed is rejected and the agent must obtain a fresh quote.
Three Cost Layers
Pricing decisions flow through three distinct values. They live in different places and serve different roles.
| Layer | Source | Role |
|---|---|---|
| Quoted cost | MeteredBillingQuote.quoted_cost | Pre-execution estimate from the metering provider, bound to the intent. |
| Observed cost | Tool server post-execution metering payload | What the tool actually consumed (token count, bytes, etc.) translated to monetary units. |
| Charged cost | Receipt metadata, capped by capability budget | What the kernel actually deducted, after applying budget caps and max_billed_units. |
These three values are reconciled after settlement. See Reconciliation for the full flow.
Budget Caps on the Capability Grant
The capability grant carries the runtime ceiling. Two fields on ToolGrant bound how much a single grant can spend.
| Field | Type | Effect |
|---|---|---|
max_cost_per_invocation | Option<MonetaryAmount> | Per-call ceiling. Rejected if a quote or receipt charges more. |
max_total_cost | Option<MonetaryAmount> | Aggregate ceiling across all invocations under this grant. |
max_invocations | Option<u32> | Maximum number of invocations under this grant. |
Where the kernel actually enforces
max_cost_per_invocation consistent with the advertised price plus a local safety margin, so a tool server that quietly raises its price loses the call instead of overrunning the budget.Cross-Currency Settlement
When the budget is denominated in one currency and the quote in another, the kernel needs an exchange rate. Chio sources rates from oracle integrations and records the source on the receipt. See Chainlink integration for the supported feed surface.
- The agent or authority requests a conversion at intent time. The kernel records the source feed, the round id, and the rate used.
- Receipts carry an
oracle_evidencefield naming the feed and the conversion that was applied. Auditors can re-verify against the same feed at the same round. - A stale or unreachable feed fails closed; the kernel refuses to invent a rate.
Worked Example: Per-Unit Pricing with a Quote
A summarization tool charges 5 cents per 1,000 tokens. The operator publishes the manifest, an authority issues a capability with a USD 5.00 ceiling, and the agent requests a quote before the call.
1. Publish the Pricing Block
{
"name": "summarize",
"description": "Returns a model-generated summary",
"input_schema": { "...": "..." },
"pricing": {
"pricing_model": "per_unit",
"unit_price": { "units": 5, "currency": "USD" },
"billing_unit": "1k_tokens"
},
"has_side_effects": false,
"latency_hint": "moderate"
}2. Issue a Capability with a Ceiling
{
"tool_grant": {
"server_id": "srv-summary",
"tool_name": "summarize",
"operations": ["invoke"],
"max_invocations": 50,
"max_cost_per_invocation": { "units": 500, "currency": "USD" },
"max_total_cost": { "units": 50000, "currency": "USD" }
}
}3. Obtain a Quote
Before invoking, the agent asks its metering provider for a pre-execution quote. The provider issues a stable MeteredBillingQuote with quoted_units = 8 (eight thousand-token blocks) and quoted_cost = USD 0.40.
4. Bind the Quote to the Intent
{
"id": "intent-2026-04-28-001",
"server_id": "srv-summary",
"tool_name": "summarize",
"purpose": "draft summary for ticket #3120",
"max_amount": { "units": 500, "currency": "USD" },
"metered_billing": {
"settlement_mode": "hold_capture",
"quote": {
"quote_id": "q-2026-04-28-991",
"provider": "metering.example",
"billing_unit": "1k_tokens",
"quoted_units": 8,
"quoted_cost": { "units": 40, "currency": "USD" },
"issued_at": 1714287000,
"expires_at": 1714287600
},
"max_billed_units": 12
}
}5. Dispatch and Settle
The kernel verifies the quote validity window, confirms the capability ceiling covers the quote, places a hold for USD 0.40, dispatches the call, and signs a receipt. Post-execution the metering provider observes nine thousand-token blocks; the tool reports observed cost USD 0.45. The kernel captures up to max_billed_units = 12, in this case the actual nine units, and records the charged cost on the receipt.
Failure Modes
- Stale quote: quote
expires_athas passed before dispatch. Kernel refuses; agent obtains a fresh quote. - Quoted cost exceeds capability ceiling: rejected at intent verification with a budget error.
- Observed cost exceeds
max_billed_units: the kernel charges the cap, marks the receipt with overrun metadata, and pauses further dispatch under the same grant until reconciliation. - Currency mismatch with no oracle: a USD budget against an EUR quote without a configured rate source fails closed.
- Provider unknown: a quote signed by a metering provider absent from the authority's trusted set is rejected.
In the Procurement Tour
This is station 3 of the Procurement Tour: buyer wraps Vanguard's quote in a GovernedTransactionIntent with a metered-billing block.
soc2-review tool and has its advertised ToolPricing in hand.Lattice issues an MCP request_quote for 1000 evidence rows. Vanguard returns a quote bound to a five-minute validity window. The buyer kernel pins it as a MeteredBillingContext on the governed intent. The settlement posture is hold_capture: an escrow hold lands before the tool runs and settles by capture or release based on observed usage.
pub enum MeteredSettlementMode {
MustPrepay,
HoldCapture,
AllowThenSettle,
}{
"id": "intent-soc2-review-001",
"server_id": "vanguard-security",
"tool_name": "soc2-review",
"purpose": "SOC 2 evidence review for Q2 release window",
"max_amount": { "units": 110, "currency": "USD" },
"metered_billing": {
"settlement_mode": "hold_capture",
"quote": {
"quote_id": "quote_vanguard_soc2_001",
"provider": "did:chio:c87a...",
"billing_unit": "evidence-row",
"quoted_units": 1000,
"quoted_cost": { "units": 100, "currency": "USD" },
"issued_at": 1745870400,
"expires_at": 1745870700
},
"max_billed_units": 1100
}
}The buyer kernel computes binding_hash() over the intent. That hash anchors the next station's federation resolution, the dispatch, and both sides of the receipt pair.
Related
- Signed Tool Manifests covers the schema that carries the pricing block.
- Capability Discovery covers the listing layer that surfaces SLA hints alongside prices.
- Reconciliation covers the post-settlement comparison of quoted, observed, and charged cost.
- Guide: Tool Pricing walks through declaring pricing in Rust, TypeScript, and Python.