Guide

How to charge customers per AI conversation instead of per token

Token counts are what the provider bills you. They are not what your customer is buying, and pricing on them creates problems nobody warns you about until the second invoice.

The invoice that looks like a bug

Two customers run the same feature: an agent that reads a support ticket and drafts a reply. Same intent, same model class. One invoice line reads $0.021. The other reads $0.087. Nothing about the outcome differed. The second draft just needed a tool retry after a timeout, and the model re-read more of the ticket history to recover context. The customer did not do anything different. Your token bill did.

That is not a pricing problem you can explain your way out of, because it is not really about price. It is that the token count is downstream of implementation variance: retries, cache misses, how many iterations the model needed, none of which the customer can see or control. Billing on it passes your infrastructure’s bad day directly to their invoice.

Charge for the unit you can actually promise

A conversation turn is bounded work: it starts when you accept the request and ends when you emit a response, and everything in between belongs to it, however many model round-trips, tool calls or retries it took. The specification’s counting rule states this as the entire boundary in one line:

One emission, one turn. Everything the system had to do to reach that emission belongs to it.

That is the unit worth pricing, because it is the unit you can actually hold constant. A turn that took three model iterations and a retried tool call is still one turn, with one price, regardless of what it cost you to produce.

Two views, one record

The customer sees a flat line item. You keep a decomposed record underneath it: every component that contributed to the cost, and what it actually spent, whether or not that number resembles what you charged.

FieldCustomer seesYou record
Unit1 conversation turnturn_id: "turn_01JCM9"
Price$0.08 flatprice_charged: 0.08
Actual costnot showncost_total: 0.0213, decomposed per component

The two numbers are allowed to diverge, on every turn, in either direction. That divergence is your margin, and it is stable precisely because the price does not move when a retry does.

What the record looks like

A submission and the record it produces, using the actual API shape:

POST /v1/turns
{ "tenant": "ten_04qf",
  "message": "Draft a reply to ticket 4821" }

// the resulting turn record (abridged)
{ "turn_id": "turn_01JCM9",
  "outcome": "emitted",
  "cost_total": 0.0213,
  "cost_components": { "inference_output": 0.0104, … },
  "price_charged": 0.08
}

Picking your classes

Most teams don’t need per-turn pricing granularity; they need two or three classes: a standard reply, a complex multi-tool resolution, maybe a bulk-import class, each priced flat. The specification calls this class_basis: whether the class follows the model that served it, the shape of the work, or what the customer selected. Declaring it is what keeps a per-class figure interpretable instead of circular. Price the class, not the call, and a retry stops being a line item your customer has to ask about.

The turn boundary and the required record fields are defined normatively in turn-accounting §3, The turn and §5.1, Required fields.