Platform

Bill your users for model tokens

Send each user's model-token usage to your Polar or Dodo account and charge them with your own prices.

Charge your customers for the model tokens they use, through your own Polar or Dodo account. Blazing Agents measures every turn, tags it with your end user, and sends one usage event to your billing provider. You set prices, allowances, and invoices there. Blazing Agents never handles your customers' payments, and your own Blazing Agents bill stays separate.

Who does what

  • Blazing Agents measures each turn's tokens, creates one usage event per turn, and keeps delivering it until your provider accepts it or you resolve it.
  • Your backend links each of your users (userId) to a customer in your billing provider.
  • Polar or Dodo turns events into charges: meters, prices, allowances, credit balances, and invoices.

Monetization is off until you turn it on. While it is off, nothing is sent to your provider.

Set up monetization

You can do every step in the dashboard under Monetization, or from your backend with the TypeScript SDK as shown here. The Python SDK does not manage monetization yet.

Create one connection with your provider, the environment (sandbox or live), and a credential:

import { BlazingAgents } from "@blazingagents/sdk";

const client = new BlazingAgents({
  apiKey: process.env.BLAZING_AGENTS_API_KEY!,
});

await client.merchantConnection.create({
  provider: "polar",
  environment: "sandbox",
  credential: process.env.POLAR_ACCESS_TOKEN!,
});
await client.tenant.patch({ monetizationEnabled: true });
  • Polar: use an Organization Access Token (polar_oat_...) with organizations:read, customers:read, and events:write, and nothing else.
  • Dodo: use an API key from your Dodo dashboard in the mode that matches the environment.

Blazing Agents checks the credential with your provider before the connection goes live. After that, only a short fragment of it is shown.

When a user signs up or starts a paid plan, create the customer in your provider, then link your userId to it:

await client.merchantBindings.put({
  userId: "app:user-42",
  customerId: "cus_from_polar_or_dodo",
});

Blazing Agents checks that the customer exists. Usage for a user with no link is held as unmapped, never sent as zero. Link the user, then release those events.

Create a meter

In your provider, create a meter for events named ba.model_tokens.v1, using the recipes below. Attach it to a price or an allowance so usage turns into charges.

Optionally require a paid plan

Turn on the guard to check each user's plan or balance with your provider before every turn starts:

await client.merchantConnection.update({
  guard: {
    enabled: true,
    productIds: ["prod_..."],
    meterId: "meter_or_credit_entitlement_id",
  },
});

See guard rules for what each setting requires.

Provider meter recipes

Every event is named ba.model_tokens.v1 and carries this flat metadata, so meters can filter and sum without nested paths:

Metadata keyTypeContents
input_tokensnumberPrompt tokens for the turn
output_tokensnumberCompletion tokens for the turn
total_tokensnumberinput_tokens + output_tokens
modelstringThe model ID
model_providerstringThe upstream model provider
ba_event_idstringThe mev_ event ID, also used to drop duplicates
turn_idstringThe turn that used the tokens
agent_idstringThe agent that ran the turn
session_idstringThe session, omitted for calls without one
statusstringThe turn outcome: succeeded, failed, or cancelled

Polar

Create a meter that filters on event name ba.model_tokens.v1 with a Sum over total_tokens. For separate prompt and completion prices, create one meter over input_tokens and one over output_tokens. Add filters on model for per-model prices, or on status to bill only succeeded turns. Then attach a metered price to a product, or grant an allowance with a metered benefit.

Polar drops duplicates by the event's external_id, which holds the mev_ ID, so a resent event is never billed twice. An event Polar accepts late is billed in the cycle it arrives.

Dodo

Create a meter with Event Name ba.model_tokens.v1 (case-sensitive) and a Sum Over Property total_tokens, or use input_tokens and output_tokens for split pricing. Attach it to a usage-based product, then set a per-unit price, or turn on Bill usage in Credits and link a Credit Entitlement for prepaid allowances. Meter filters can match model or status.

Dodo drops duplicates by event_id, the mev_ ID. Dodo rejects events older than one hour, so an event that misses that window is marked expired and needs a correction in Dodo.

Guard rules

RuleproductIdsmeterIdA turn is allowed when
Subscription onlyone or morenullThe customer has an active subscription to a listed product. Otherwise: merchant_subscription_required.
Balance onlyemptysetThe meter or credit balance is above zero. Otherwise: merchant_balance_required.
Bothone or moresetBoth conditions hold.

On Polar, meterId is the meter shown in the customer's state. On Dodo, it is the credit entitlement ID. A user with no linked customer gets merchant_customer_unmapped.

The guard checks only when a turn starts. A turn can still run past a balance while it runs. If your provider cannot be reached, the turn is refused with merchant_eligibility_unavailable.

Delivery states

client.merchantUsageEvents.list() shows every event with a status and a suggested nextAction:

StatusMeaningNext action
pendingWaiting or being deliveredwait, or retry once automatic delivery gives up
acceptedYour provider confirmed itnone
uncertainA temporary failure, and the event may have arrivedretry, which is safe because duplicates are dropped
failedYour provider rejected it, for example because of a revoked credentialretry after you fix the cause
unmappedNo customer linked to the userIdbind_and_release: link the user, then call release
incompleteThe event could not be builtinvestigate
expiredDodo's one-hour window passeddiscard, then correct it in Dodo
discardedYou discarded it, or monetization was offnone

Events never change after they are created. For an uncertain event, you can check your provider first: Dodo can look up events by event_id, and Polar can search by the ba_event_id metadata.

Things to know

  • Turning monetization off discards every event your provider has not accepted yet. Your connection and customer links stay, but turning it back on does not recover discarded events or backfill usage.
  • An accepted event means your provider received it. It is not proof of an invoice, so settle billing disputes in your provider.
  • unmapped and incomplete events wait in the list until you link, retry, or discard them.
  • Deleting your account is scheduled 24 hours ahead and can be cancelled until then. Unresolved events are deleted with the account, and usage still arriving at that point is not billed.

Next

On this page