Kaiten

Monetization

Prices

What a License version costs — flat fees per billing period, usage-based and overage prices on a metered entitlement — their timing, periods, currency, defaults, the rules that freeze them, and the invoice preview, verified against the API.

A price hangs on a License version and is one billable concern: one line of an invoice. A version carries several, all in one currency — flat fees, one of which each subscription to the version is pinned to as its base, and metered prices, which bill the usage of an entitlement on every subscription to the version. Prices need billing to be on; they are read with read:licenses and written with write:licenses.

Examples use $KAITEN_API and $KAITEN_TOKEN as set up in the quickstart, on a stack where billing is on. The demo seed writes Kaiten Sushi Shop's prices: on a seeded stack they already exist on Standard v1, so read them with GET /licenses/standard/prices, or follow the calls below on a version of your own. Responses are illustrative — ids and timestamps depend on your stack.

Three shapes

A price's billingModel says what it bills:

billingModelBillsBilling periodTimingKaiten Sushi Shop
FLAT_FEEAn amount per billing period, at a quantity of 1Its own: MONTHLY, QUARTERLY, SEMI_ANNUAL, or ANNUALADVANCE by default, or ARREARSStandard, monthly — 49.00 EUR a month
USAGE_BASEDAn amount per sale unit of a metered entitlement's usage, from the first unitNone: it bills over the period of the subscriptionARREARS—
OVERAGEAn amount per sale unit of the usage above the grant's valueNoneARREARSOrders above the allowance — 0.50 EUR per order of monthly-orders

Timing. ADVANCE bills the period that starts at a boundary, ARREARS the period that ends there. A metered price is always ARREARS — usage cannot be billed before it happens — and is created so when billingTiming is omitted; a flat fee defaults to ADVANCE. Any other combination is refused (422 CreateLicensePrice.InvalidTiming). A subscription whose base bills in advance gets its first invoice when it starts; one whose base bills in arrears gets nothing before its first period closes.

Periods. A flat fee is charged for its billingPeriod — one, three, six, or twelve months, counted from the subscription's anchor, the day clamped to the end of a shorter month. A metered price has none (billingPeriod: null): it bills over the period of the subscription's base price. A period is required on a flat fee and refused on a metered price (422 CreateLicensePrice.InvalidPeriod).

Amounts and currency

No amount is a float (API conventions). A price is created with unitAmountDecimal, a decimal string in the currency's minor units — "4900" is 49.00 EUR, "50" is 0.50 EUR — of at most 12 integer digits and 12 decimal places, so a fraction of a cent per unit can be priced (422 CreateLicensePrice.InvalidAmount otherwise). The response repeats it as unitAmount, an integer, when it is a whole number of minor units, and null otherwise. On an invoice, a line's amount is its quantity times the unit amount, rounded half up once.

currency is an ISO 4217 code in upper case (422 CreateLicensePrice.InvalidCurrency). A version bills in one currency, fixed by its first price: a price in another one is refused (422 CreateLicensePrice.CurrencyMismatch), deprecated prices included. Every price of a FREE version is 0 (422 CreateLicensePrice.FreePriceNotZero) — see the pricing type.

Create a price

POST /licenses/{slug}/prices adds a price to a version. Standard v1 sells two flat fees, each the default of its period:

curl -X POST "$KAITEN_API/licenses/standard/prices" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "billingModel": "FLAT_FEE",
    "billingPeriod": "MONTHLY",
    "currency": "EUR",
    "unitAmountDecimal": "4900",
    "displayLabel": "Standard, monthly",
    "displayOrder": 1,
    "isDefault": true
  }'

Standard, yearly is the same call with ANNUAL, "49000", and a displayOrder of 2. Then the orders above Standard's allowance:

curl -X POST "$KAITEN_API/licenses/standard/prices" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "billingModel": "OVERAGE",
    "meteredEntitlementSlug": "monthly-orders",
    "currency": "EUR",
    "unitAmountDecimal": "50",
    "displayLabel": "Orders above the allowance",
    "displayOrder": 3
  }'
{
  "id": "8c2d4e6f-1a3b-4c5d-9e7f-0a1b2c3d4e5f",
  "billingModel": "OVERAGE",
  "billingTiming": "ARREARS",
  "billingPeriod": null,
  "currency": "EUR",
  "unitAmount": 50,
  "unitAmountDecimal": "50",
  "metered": {
    "entitlementSlug": "monthly-orders",
    "saleUnitFactor": "1",
    "saleUnitSingular": "order",
    "saleUnitPlural": "orders"
  },
  "displayLabel": "Orders above the allowance",
  "displayOrder": 3,
  "isDefault": false,
  "status": "ACTIVE",
  "deprecatedAt": null,
  "createdAt": "2026-09-08T10:01:00Z",
  "updatedAt": "2026-09-08T10:01:00Z"
}

HTTP/1.1 201 Created, and LICENSE_PRICE_CREATED is emitted. The timing was omitted, so the metered price bills in ARREARS; it has no period of its own, and metered says what it measures. monthly-orders has no sale unit, so the price bills per order: a factor of 1.

In the console, the Prices tab of a version lists its prices, and Add price opens the New price drawer: the shape, the timing, the period, the currency, the label, the amount — typed in the currency's own unit and sent in minor units — and the default flag.

The New price drawer on the Prices tab of the draft Premium v3: Flat fee, billed in advance, Annual, EUR, labelled Premium, yearly, at 3200.00 — read back as €3,200.00/year — and checked as the default price of its period.The New price drawer on the Prices tab of the draft Premium v3: Flat fee, billed in advance, Annual, EUR, labelled Premium, yearly, at 3200.00 — read back as €3,200.00/year — and checked as the default price of its period.

What a metered price measures

A USAGE_BASED or OVERAGE price names the entitlement it measures, meteredEntitlementSlug, and bills its usage over the period that ended, read from the usage journal. Only a flow can be metered — a count that starts over every window:

  • a NUMBER or NUMBER_AI_CREDIT entitlement (422 CreateLicensePrice.UnsupportedEntitlementType otherwise);
  • with a reset period (.EntitlementIsStock otherwise — a count that never resets, such as delivery-drivers, is a stock, sold as an add-on held in a quantity);
  • aggregated with SUM or COUNT (.UnsupportedAggregation otherwise);
  • granted by the version (.EntitlementNotGranted; an entitlement that does not exist answers 404 Not Found, .EntitlementNotFound);
  • and metered by no other active price of the version (.EntitlementAlreadyMetered): one metered price per entitlement.

An OVERAGE price also needs a grant that usage can pass: a finite value with an overage allowance above 0. A hard cap or an unlimited grant never goes above its value, so the price is refused (422 CreateLicensePrice.OverageUnreachable). Once an active price meters an entitlement, the version keeps its grant until the price is deprecated (409 DeleteLicenseEntitlement.MeteredByPrice).

Sale units. A metered price is priced per sale unit of its entitlement. An entitlement can be counted in one unit and sold in another — counted in tokens, sold per 10,000 tokens — through its sale unit (saleUnitSingular, saleUnitPlural, saleUnitFactor, on the entitlement); the line's quantity is then the usage divided by the factor. The factor is captured on the price when it is created, as metered.saleUnitFactor, and a later change to the entitlement never reprices it. An entitlement without a sale unit is billed in its base unit, with a factor of 1, and its prices carry no unit label. monthly-orders names the order as its sale unit, with a factor of 1, so its overage price reads per order.

What the grant lets through. A usage report beyond what the grant accepts is refused before it is stored, so a metered price only ever bills what the grant let through. Standard grants monthly-orders at 100 with a 10 % allowance: reports are accepted up to 110 orders a month, and Orders above the allowance bills each order above 100 — at most 10 a month, 5.00 EUR. The overage is counted against the limit in force when each report was accepted, which the invoice line lists.

The Prices tab of Standard v1: the summary €49.00/month or €490.00/year + €0.50 per order above the allowance, the note that the prices of a published version are immutable, and three active prices — Standard, monthly and Standard, yearly, each the default of its period, and Orders above the allowance, an overage on Monthly Orders that bills above 100 orders/month, up to 110, in arrears.The Prices tab of Standard v1: the summary €49.00/month or €490.00/year + €0.50 per order above the allowance, the note that the prices of a published version are immutable, and three active prices — Standard, monthly and Standard, yearly, each the default of its period, and Orders above the allowance, an overage on Monthly Orders that bills above 100 orders/month, up to 110, in arrears.

The default price of each period

isDefault marks a flat fee as the default of its billing period: at most one per period and version (409 CreateLicensePrice.DefaultConflict), and only an active flat fee (422 .InvalidDefault on a metered price). The default is the price taken when none is named: the public catalogue shows the default flat fee of each period, an anonymous checkout that names a version and a period buys it, and the invoice preview starts from the version's first default in display order. Standard v1 has two defaults — Standard, monthly for MONTHLY, Standard, yearly for ANNUAL. Deprecating a default takes the flag away in the same write.

Label and order

displayLabel, up to 200 characters, is the label of the invoice line the price produces. Left out, the line derives one: the License name and — base for a flat fee (Standard — base), the entitlement's name for a usage-based price, and the entitlement's name and — overage for an overage price (Monthly Orders — overage). displayOrder, 0 or more, orders the version's prices — in GET /licenses/{slug}/prices, the console, and the public catalogue.

What a version lets you change

Prices follow the lifecycle of their version, and a subscription freezes what it bills:

VersionAdd a priceEdit a priceDeprecate a price
DRAFTYesYesYes
PUBLISHEDYes, until a subscription bills the version — then 409 CreateLicensePrice.BillingActiveNo — 409 UpdateLicensePrice.VersionNotDraftYes
ARCHIVEDNo — 409 CreateLicensePrice.VersionArchivedNoYes

PATCH /licenses/{slug}/prices/{priceId} edits a price of a draft: its amount, timing, period, metered entitlement, label, order, or default flag — never its shape or its currency, which make another price. A published price never changes under what is billed from it: its only change is deprecation. To sell other terms, create a new version.

Deprecate, never delete. POST /licenses/{slug}/prices/{priceId}/deprecate retires a price for good. It is no longer offered — to a new subscription, a checkout, or a move to another price — and it stops being a default. A subscription pinned to a deprecated flat fee keeps being billed from it; a deprecated metered price bills no line from the next invoice on. A price that a subscription is scheduled to move to cannot be deprecated until the change is dropped (409 DeprecateLicensePrice.PlanChangeTarget), and deprecating a price twice answers 409 DeprecateLicensePrice.AlreadyDeprecated. No operation deletes a price: a version's prices go with it when the version is deleted.

Preview an invoice

POST /licenses/{slug}/invoice-preview composes the renewal invoice a subscription to the version would be billed at a boundary now, and writes nothing. It works on a draft — to check prices before they become immutable — and needs read:licenses. Every member of the body is optional:

MemberWhat it addsRefused with
basePriceIdThe flat fee billed as the base; when omitted, the version's first default flat fee in display orderPriceNotFound; NoBasePrice when the version has no default flat fee
sampleUsageUsage of each metered entitlement over the period that ends, as decimal strings, rated as one window against the grant — usage beyond what the grant accepts is capped, and the line says soInvalidSampleUsage
instanceSlugAn instance's own usage instead of a sample, from the start of its current billing period — or from one billing period back when it has no subscriptionInstanceNotFound; OutsideRetention when that start is older than the usage kept
addOnsAdd-on versions and their quantities: their fees and metered prices are priced in, and their grants raise the limit a sample is rated againstAddonNotFound, InvalidAddOns
voucherCodeA voucher's price discount, applied as a redemption would apply it — nothing is redeemedVoucherNotFound, VoucherInvalid

The codes are PreviewLicenseInvoice.*: 404 Not Found for what does not exist, 422 Unprocessable Entity otherwise. Rate a month of 106 orders on Standard v1:

curl -X POST "$KAITEN_API/licenses/standard/invoice-preview" \
  -H "Authorization: Bearer $KAITEN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"sampleUsage": [{"entitlementSlug": "monthly-orders", "quantity": "106"}]}'
{
  "status": "PREVIEW",
  "kind": "RENEWAL",
  "asOf": "2026-09-08T10:00:00Z",
  "boundaryAt": "2026-09-08T10:00:00Z",
  "licenseSlug": "standard",
  "currency": "EUR",
  "subtotal": 5200,
  "discountTotal": 0,
  "total": 5200,
  "lines": [
    {
      "seq": 1,
      "type": "OVERAGE",
      "label": "Orders above the allowance",
      "description": "6 × 0.50 EUR; 106 used; 6 above the applied limit (100)",
      "serviceFrom": "2026-08-08T10:00:00Z",
      "serviceTo": "2026-09-08T10:00:00Z",
      "quantity": "6",
      "unitAmountDecimal": "50",
      "amount": 300
    },
    {
      "seq": 2,
      "type": "BASE",
      "label": "Standard, monthly",
      "description": "1 × 49.00 EUR",
      "serviceFrom": "2026-09-08T10:00:00Z",
      "serviceTo": "2026-10-08T10:00:00Z",
      "quantity": "1",
      "unitAmountDecimal": "4900",
      "amount": 4900
    }
  ],
  "wouldHold": []
}

HTTP/1.1 200 OK, trimmed here to the members discussed: each line also carries the identifiers of its price and entitlement, and a metered line its metering and overage detail. The base is Standard, monthly, the first default in display order, billed in advance for the period that starts; the orders are rated in arrears for the period that ends — 106, of which 6 above the 100 Standard grants, at 0.50 EUR: 3.00 EUR. A sample of 125 would be capped at 110, the most the grant accepts, and its line would say so. Nothing is created: status is always PREVIEW, and wouldHold — the meters whose usage journal would hold the invoice — is always empty for a sample.

The Preview invoice button of the Prices tab runs the same call, from samples or from an instance's usage, with add-ons and a promo code:

The Preview an invoice dialog over Standard v1's Prices tab: base price Standard, monthly at €49.00, a sample of 106 Monthly Orders, and the renewal invoice composed by the API — Orders above the allowance, 6 × 0.50 EUR, €3.00, and the Standard, monthly base, €49.00, for a total of €52.00.The Preview an invoice dialog over Standard v1's Prices tab: base price Standard, monthly at €49.00, a sample of 106 Monthly Orders, and the renewal invoice composed by the API — Orders above the allowance, 6 × 0.50 EUR, €3.00, and the Standard, monthly base, €49.00, for a total of €52.00.

API endpoints

MethodEndpointOperationDescription
GET/licenses/{slug}/priceslistLicensePricesA version's prices, in display order; ?status= and ?billingModel= narrow the list
GET/licenses/{slug}/prices/{priceId}getLicensePriceOne price, deprecated or not
POST/licenses/{slug}/pricescreateLicensePriceAdd a price to a version
PATCH/licenses/{slug}/prices/{priceId}updateLicensePriceEdit a price of a draft
POST/licenses/{slug}/prices/{priceId}/deprecatedeprecateLicensePriceRetire a price, for good
POST/licenses/{slug}/invoice-previewpreviewLicenseInvoiceCompose the invoice a subscription to the version would be billed, writing nothing

The reads and the preview need read:licenses, the writes write:licenses, and every one of them billing to be on — 403 Billing.Disabled or 403 Billing.NotEntitled otherwise.

Events

Event nameEvent typeWhen
LICENSE_PRICE_CREATEDcom.kaiten.license.price.v1.createdA price is added to a version
LICENSE_PRICE_UPDATEDcom.kaiten.license.price.v1.updatedA price of a draft is edited; changedFields names what changed, and an edit that changes nothing emits none
LICENSE_PRICE_DEPRECATEDcom.kaiten.license.price.v1.deprecatedA price is deprecated

Each carries the price as the API returns it, with the licenseSlug of its version and the familySlug of its family.

Where to go next

Put a tier's prices next to its grants: Pricing Tiers. Bill them: Subscriptions and Invoices. How a version is sold — its pricing type and its trial: License Types. Exact reference: the billing tables of the data model.

On this page