Zum Inhalt
Lumean API

Tokens, quotas, LMC and PAYG

A token is not a ruble and not LMC. What is charged to the subscription quota, what to the balance, and how to get through the 402 payg_topup_required fork without paying twice.

Übersetzung in Arbeit

Diese Seite ist noch nicht in Ihre Sprache übersetzt — die Fassung unten ist auf English. Text und Codebeispiele sind dieselben.

Billing in the public API involves three different quantities, and they are regularly confused with one another.

QuantityWhat it isWhere to see it
Tokenan accounting unit of a service's work volume. Not money and not LMCtotal_tokens, tokens_spent in the order; GET /usage
Subscription quotathe plan's token allowance for the billing period. Spent first, free of chargeGET /subscriptions → items[].tokens_remaining
LMCthe internal currency. Only what the quota didn't cover is paid from itshortfall_lmc in the 402 response; price_formatted in the order

The charge order is always the same and can't be configured: subscription quota first, LMC only for the remainder. If the quota is sufficient, the balance isn't touched at all, and the confirm_payg_topup flag changes nothing.

Stolperfalle

The public API doesn't show your LMC balance: GET /wallets and GET /ledger-transactions return 404 in the standard configuration. The public view of your state is GET /usage and GET /subscriptions, and you learn the top-up amount from the 402 body, not from the balance in advance.

If the order costs more than the tokens left in the quota, and the service allows pay-as-you-go (Service.payg_access ≠ disabled), the server doesn't create the order and charges nothing; instead it returns 402 with the top-up price. It's not a rejection but a question.

Die PAYG-Weiche nach einem 402Ein 402 liefert shortfall_lmc und quote_token; die Wiederholung mit confirm_payg_topup ergibt 201, ein abgelaufenes Angebot 409.POST /orders402 payg_topup_requiredshortfall_lmc · quote_tokenquote_token lebt etwa 60 Sekundenconfirm_payg_topup: true+ quote_tokenrechtzeitigzu spät201 Created201 — Auftrag erstellt, Aufstockung abgerechnet409 quote_mismatch409 quote_mismatch — neues Angebot anfordern

The 402 body:

FieldMeaning
reasonalways payg_topup_required — branch on it, not on message
shortfall_tokenshow many tokens the quota didn't cover — exactly these are paid from LMC
shortfall_lmcthe top-up price in LMC, ready to show to the user
shortfall_lmc_minorthe same amount in minor units — for exact calculations
quote_tokena signed quote; send the string back unchanged
expires_atthe price is locked until this moment (the token lives ~60 seconds)

If you agree, repeat the exact same request with two added fields:

# 1. Regular attempt → HTTP 402 with a quote
curl -s -X POST "$BASE/orders" -H "X-API-KEY: $KEY" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "<UUID>", "input_text": "…" }'

# 2. Consent: the same body + confirmation and the same quote_token → HTTP 201
curl -s -X POST "$BASE/orders" -H "X-API-KEY: $KEY" \
  -H "Content-Type: application/json" \
  -d '{ "template_id": "<UUID>", "input_text": "…",
        "confirm_payg_topup": true, "quote_token": "q_9f8b2c1a4d3e" }'

If you don't agree, simply don't repeat the request: the order wasn't created, nothing was charged, there's nothing to cancel.

402payg_topup_requiredpayg_topup_required — PAYG top-up required
Was passiert ist
The order was not created and no money was charged — instead, the server sent the price of the top-up. Body: `reason: "payg_topup_required"`, `shortfall_tokens`, `shortfall_lmc`, `shortfall_lmc_minor`, `quote_token`, `expires_at`.
Was jetzt zu tun ist
Show the user `shortfall_lmc` and get explicit consent — an automatic retry here means silently charging money. The quote is short-lived (`expires_at`, on the order of a minute); if it has expired, a repeat request WITHOUT confirmation returns a fresh 402 with a new `quote_token`.
Code-Seite öffnen

Four confirmation traps

  1. The flag alone charges nothing. confirm_payg_topup: true without a quote_token — or with one that has expired, been modified, or was issued for a different order — returns 402 again with a new quote.
  2. Consent is an upper bound, not a fixed amount. If the top-up has become cheaper by the time of the charge, the actual price is charged. If it has become more expensive, you get 409 quote_mismatch with the fields actual_lmc_minor and quoted_lmc_minor.
  3. Repeating without confirmation is safe and is a standard step: it issues a fresh 402. That's exactly how you refresh a stale or more expensive price — re-sending the old quote_token is pointless.
  4. POST /orders/{order}/retry has the same flow — an order retry goes through the same billing and can likewise answer 402 and 409.
409quote_mismatchquote_mismatch — top-up quote is stale
Was passiert ist
The confirmed top-up did not go through: the order was not created and nothing was charged. Body: `reason: "quote_mismatch"`, `actual_lmc_minor` (what it costs now), `quoted_lmc_minor` (what it was in the quote).
Was jetzt zu tun ist
The difference `actual_lmc_minor − quoted_lmc_minor` is the price increase; it is in minor units, and what you should show the user is `shortfall_lmc` from the next quote. The old `quote_token` is no longer valid: submitting it again guarantees the same 409.
Code-Seite öffnen

Three different branches under code 402

These get confused most often: the code is the same, the reason differs, and the remedies are incompatible.

reasonWhat happenedWhat to do
payg_topup_requiredthe quota ran short, a top-up is allowedconfirm the top-up with the quote
insufficient_balancethe LMC balance lacks funds for the order's reservetop up the wallet or reduce the order volume
insufficient_allowancethe quota ran short, and PAYG is disabled for the servicethere's nothing to top up with: wait for the new period, change the plan or cut the text

You can tell insufficient_allowance apart from a top-up offer by the body's contents: the shortfall_*, quote_token and expires_at fields are absent. A confirm_payg_topup sent along with such a request is simply ignored by the server.

Two more domain rejections live nearby, but with code 403: no_subscription and entitlement_missing — there's no subscription, or no required plan feature, at all. And limit_exceeded with code 429 isn't about money but a subscription usage limit; see Limits and the 429 code.

Minor units: why shortfall_lmc_minor can't be shown as is

All monetary fields in the API are integers in the asset's minor units. The real value is calculated as minor / 10 ** precision. In the spec example, shortfall_lmc_minor: 360000000 corresponds to shortfall_lmc: 3.6, which means the divisor here is 10^8, not 100.

Vorsicht

precision is not two and is not a constant — it lives in the data: on an order in currency_asset.precision, on a service rate in the lumc_precision field. A formula dividing by 100 gives an amount that is off by a factor of a million, and showing 360000000 to the user as rubles is even worse. For display, use the ready-made shortfall_lmc and price_formatted; the minor-unit fields are only for arithmetic.

Where to check the remainder before ordering

GET/subscriptionsGet subscriptions of API key owner

Get subscriptions of API key owner

Only live subscriptions are returned (status active, not expired). The remainder is in items[].token_allowance, tokens_used, tokens_remaining. There are no monetary fields here, by design.

GET /usage lists limits: limit_type, limit_value, used, remaining, period_start / period_end / resets_in, plus token_unlimited and is_exceeded. It also shows which services are available to you at all — the set is defined by the subscription's entitlements. For a single service, use GET /usage/{service}, where {service} is the service_code from the GET /usage output (elevenlabs, heygen, lumimg, sfx, music, voice_search), not an arbitrary string.

Stolperfalle

The LLM reference (§7.7) calls {service} the service's integer id. That's wrong: in the spec the parameter is a string, and the path accepts the service code — the same one found in the template's service_key. A numeric id gives 404.

You can estimate the top-up in advance from the service rate: shortfall_tokens × lumcoin_per_token (the lumcoin_per_token field is also in LMC minor units).

What's visible after the fact, in the order itself

  • total_tokens — the full cost in tokens, including retries and regenerations;
  • tokens_spent — actually spent (retry repeats aren't charged again);
  • tokens_from_quota and tokens_from_payg — the split into the free and paid portions;
  • price_units — the locked PAYG amount in minor units, price_formatted — the same amount for display.

Stolperfalle

A zero portion arrives as null, not 0. For an order fully covered by the quota, tokens_from_payg is null; for pure PAYG, tokens_from_quota is null. The check if (order.tokens_from_payg > 0) won't behave on null the way you expect.

Richtig

Show the user shortfall_lmc, wait for explicit consent, and repeat the request with the quote_token from that same response. If the quote has expired, request a new one by repeating without confirmation.

Falsch

Automatically retry a 402 with confirm_payg_topup: true: that's silently charging money behind the user's back, and the first price discrepancy will turn the loop into a stream of 409s.

Topping up the balance and buying a plan aren't available with an API key — the public surface doesn't process payments. That's done in the dashboard: wallet, plans, account limits.

Diese Seite einer KI geben

.md öffnenllm.md

Aktualisiert 04.09.2026 · Spezifikation 0.0.1